parent
19f5c68ac4
commit
2839a55803
@ -1,127 +0,0 @@
|
|||||||
import argparse
|
|
||||||
import os
|
|
||||||
import cv2
|
|
||||||
import numpy as np
|
|
||||||
import onnxruntime
|
|
||||||
from paddleocr.ppocr.data.imaug.operators import (
|
|
||||||
E2EResizeForTest, KeepKeys, NormalizeImage, ToCHWImage
|
|
||||||
)
|
|
||||||
# from ppocr.data.imaug.operators import (
|
|
||||||
# E2EResizeForTest, KeepKeys, NormalizeImage, ToCHWImage
|
|
||||||
# )
|
|
||||||
from paddleocr.ppocr.postprocess.pg_postprocess import PGPostProcess
|
|
||||||
# from ppocr.postprocess.pg_postprocess import PGPostProcess
|
|
||||||
from pgnet.chr_dct import chr_dct_list
|
|
||||||
|
|
||||||
|
|
||||||
class PGNetPredictor:
|
|
||||||
def __init__(self, model_path, cpu=False):
|
|
||||||
self.model_path = model_path
|
|
||||||
self.dict_path = "ic15_dict.txt"
|
|
||||||
|
|
||||||
if not os.path.exists(self.dict_path):
|
|
||||||
with open(self.dict_path, "w") as f:
|
|
||||||
f.writelines(chr_dct_list)
|
|
||||||
|
|
||||||
providers = ["CPUExecutionProvider"] if cpu else ["CUDAExecutionProvider"]
|
|
||||||
self.sess = onnxruntime.InferenceSession(model_path, providers=providers)
|
|
||||||
|
|
||||||
self.transforms = [
|
|
||||||
E2EResizeForTest(max_side_len=768, valid_set="totaltext"),
|
|
||||||
NormalizeImage(scale=1/255.0, mean=[0.485,0.456,0.406],
|
|
||||||
std=[0.229,0.224,0.225], order="hwc"),
|
|
||||||
ToCHWImage(),
|
|
||||||
KeepKeys(keep_keys=["image", "shape"]),
|
|
||||||
]
|
|
||||||
|
|
||||||
self.pgpostprocess = PGPostProcess(
|
|
||||||
character_dict_path=self.dict_path,
|
|
||||||
valid_set="totaltext",
|
|
||||||
score_thresh=0.5,
|
|
||||||
mode="fast",
|
|
||||||
)
|
|
||||||
|
|
||||||
def preprocess(self, img):
|
|
||||||
self.ori_im = img.copy()
|
|
||||||
data = {"image": img}
|
|
||||||
|
|
||||||
for transform in self.transforms:
|
|
||||||
data = transform(data)
|
|
||||||
|
|
||||||
img, shape_list = data
|
|
||||||
return np.expand_dims(img, axis=0), np.expand_dims(shape_list, axis=0)
|
|
||||||
|
|
||||||
def predict(self, img):
|
|
||||||
ort_inputs = {self.sess.get_inputs()[0].name: img}
|
|
||||||
outputs = self.sess.run(None, ort_inputs)
|
|
||||||
|
|
||||||
return {
|
|
||||||
"f_border": outputs[0],
|
|
||||||
"f_char": outputs[1],
|
|
||||||
"f_direction": outputs[2],
|
|
||||||
"f_score": outputs[3],
|
|
||||||
}
|
|
||||||
|
|
||||||
def clip_boxes(self, boxes, shape):
|
|
||||||
h, w = shape[:2]
|
|
||||||
clipped = []
|
|
||||||
for box in boxes:
|
|
||||||
box[:, 0] = np.clip(box[:, 0], 0, w - 1)
|
|
||||||
box[:, 1] = np.clip(box[:, 1], 0, h - 1)
|
|
||||||
clipped.append(box)
|
|
||||||
return np.array(clipped)
|
|
||||||
|
|
||||||
def postprocess(self, preds, shape_list):
|
|
||||||
result = self.pgpostprocess(preds, shape_list)
|
|
||||||
pts, texts = result["points"], result["texts"]
|
|
||||||
return self.clip_boxes(pts, self.ori_im.shape), texts
|
|
||||||
|
|
||||||
def infer(self, img):
|
|
||||||
img_input, shape = self.preprocess(img)
|
|
||||||
preds = self.predict(img_input)
|
|
||||||
return self.postprocess(preds, shape)
|
|
||||||
|
|
||||||
|
|
||||||
def draw_results(frame, boxes, texts):
|
|
||||||
for box, text in zip(boxes, texts):
|
|
||||||
box = box.astype(int).reshape(-1, 1, 2)
|
|
||||||
cv2.polylines(frame, [box], True, (255,255,0), 2)
|
|
||||||
cv2.putText(frame, text, tuple(box[0][0]), cv2.FONT_HERSHEY_SIMPLEX,
|
|
||||||
0.7, (0,255,0), 2)
|
|
||||||
return frame
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
parser = argparse.ArgumentParser(description="PGNet Video OCR")
|
|
||||||
parser.add_argument("--model", type=str, required=True)
|
|
||||||
parser.add_argument("--video", type=str, required=True)
|
|
||||||
parser.add_argument("--cpu", action="store_true")
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
predictor = PGNetPredictor(args.model, args.cpu)
|
|
||||||
|
|
||||||
cap = cv2.VideoCapture(args.video)
|
|
||||||
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
|
|
||||||
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
|
|
||||||
fps = cap.get(cv2.CAP_PROP_FPS)
|
|
||||||
|
|
||||||
out_name = os.path.splitext(os.path.basename(args.video))[0] + "_pgnet_output.mp4"
|
|
||||||
out_path = os.path.join(os.path.dirname(args.video), out_name)
|
|
||||||
|
|
||||||
writer = cv2.VideoWriter(out_path, cv2.VideoWriter_fourcc(*"mp4v"), fps, (width, height))
|
|
||||||
|
|
||||||
print(f"▶ Processing video... (Output: {out_path})")
|
|
||||||
|
|
||||||
while True:
|
|
||||||
ret, frame = cap.read()
|
|
||||||
if not ret:
|
|
||||||
break
|
|
||||||
|
|
||||||
boxes, texts = predictor.infer(frame)
|
|
||||||
frame = draw_results(frame, boxes, texts)
|
|
||||||
writer.write(frame)
|
|
||||||
|
|
||||||
cap.release()
|
|
||||||
writer.release()
|
|
||||||
|
|
||||||
print("🎉 Done! Video saved:", out_path)
|
|
||||||
@ -1,39 +0,0 @@
|
|||||||
import torch
|
|
||||||
from torchvision import datasets, transforms
|
|
||||||
from torch.utils.data import DataLoader
|
|
||||||
import os
|
|
||||||
|
|
||||||
def get_face_dataloaders(data_dir, batch_size=64, num_workers=4):
|
|
||||||
"""
|
|
||||||
Input: data_dir (e.g., ~/face_exp/datasets)
|
|
||||||
Structure assumed: data_dir/CASIA-WebFace/ID/images.jpg
|
|
||||||
"""
|
|
||||||
|
|
||||||
# 1. Train Transform (Augmentation + Resize to 128x128)
|
|
||||||
train_transform = transforms.Compose([
|
|
||||||
transforms.Resize((128, 128), interpolation=transforms.InterpolationMode.BICUBIC),
|
|
||||||
transforms.RandomHorizontalFlip(p=0.5),
|
|
||||||
transforms.ColorJitter(brightness=0.1, contrast=0.1, saturation=0.1),
|
|
||||||
transforms.ToTensor(),
|
|
||||||
transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])
|
|
||||||
])
|
|
||||||
|
|
||||||
# 2. Path Setup
|
|
||||||
train_dir = os.path.join(data_dir, 'CASIA-WebFace')
|
|
||||||
|
|
||||||
if not os.path.exists(train_dir):
|
|
||||||
raise FileNotFoundError(f"데이터셋 경로를 찾을 수 없습니다: {train_dir}\n'CASIA-WebFace' 폴더가 해당 위치에 있는지 확인해주세요.")
|
|
||||||
|
|
||||||
# 3. Dataset & Loader
|
|
||||||
train_dataset = datasets.ImageFolder(root=train_dir, transform=train_transform)
|
|
||||||
|
|
||||||
train_loader = DataLoader(
|
|
||||||
train_dataset,
|
|
||||||
batch_size=batch_size,
|
|
||||||
shuffle=True,
|
|
||||||
num_workers=num_workers,
|
|
||||||
pin_memory=True,
|
|
||||||
drop_last=True
|
|
||||||
)
|
|
||||||
|
|
||||||
return train_loader, len(train_dataset.classes)
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,149 +0,0 @@
|
|||||||
import torch
|
|
||||||
import torch.nn as nn
|
|
||||||
import torch.nn.functional as F
|
|
||||||
import math
|
|
||||||
|
|
||||||
# --------------------------------------------------------
|
|
||||||
# Basic Blocks (Quantization Friendly: ReLU used)
|
|
||||||
# --------------------------------------------------------
|
|
||||||
def conv3x3(in_planes, out_planes, stride=1):
|
|
||||||
return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride,
|
|
||||||
padding=1, bias=False)
|
|
||||||
|
|
||||||
class Bottleneck(nn.Module):
|
|
||||||
expansion = 4
|
|
||||||
|
|
||||||
def __init__(self, inplanes, planes, stride=1, downsample=None):
|
|
||||||
super(Bottleneck, self).__init__()
|
|
||||||
# Kernel size restricted to 1 and 3 for board compatibility
|
|
||||||
self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False)
|
|
||||||
self.bn1 = nn.BatchNorm2d(planes)
|
|
||||||
self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, padding=1, bias=False)
|
|
||||||
self.bn2 = nn.BatchNorm2d(planes)
|
|
||||||
self.conv3 = nn.Conv2d(planes, planes * self.expansion, kernel_size=1, bias=False)
|
|
||||||
self.bn3 = nn.BatchNorm2d(planes * self.expansion)
|
|
||||||
# self.relu = nn.ReLU(inplace=True) # PReLU -> ReLU
|
|
||||||
self.relu = nn.ReLU(inplace=False) # PReLU -> ReLU
|
|
||||||
self.downsample = downsample
|
|
||||||
self.stride = stride
|
|
||||||
|
|
||||||
def forward(self, x):
|
|
||||||
residual = x
|
|
||||||
out = self.conv1(x)
|
|
||||||
out = self.bn1(out)
|
|
||||||
out = self.relu(out)
|
|
||||||
out = self.conv2(out)
|
|
||||||
out = self.bn2(out)
|
|
||||||
out = self.relu(out)
|
|
||||||
out = self.conv3(out)
|
|
||||||
out = self.bn3(out)
|
|
||||||
if self.downsample is not None:
|
|
||||||
residual = self.downsample(x)
|
|
||||||
out += residual
|
|
||||||
out = self.relu(out)
|
|
||||||
return out
|
|
||||||
|
|
||||||
# --------------------------------------------------------
|
|
||||||
# Backbone: Modified ResNet-50
|
|
||||||
# --------------------------------------------------------
|
|
||||||
class ResNetFace(nn.Module):
|
|
||||||
def __init__(self, block, layers, embedding_size=128):
|
|
||||||
super(ResNetFace, self).__init__()
|
|
||||||
self.inplanes = 64
|
|
||||||
|
|
||||||
# Stem Block: 7x7 replaced by three 3x3 convs
|
|
||||||
self.stem = nn.Sequential(
|
|
||||||
nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False),
|
|
||||||
nn.BatchNorm2d(64),
|
|
||||||
# nn.ReLU(inplace=True),
|
|
||||||
nn.ReLU(inplace=False),
|
|
||||||
nn.Conv2d(64, 64, kernel_size=3, stride=1, padding=1, bias=False),
|
|
||||||
nn.BatchNorm2d(64),
|
|
||||||
# nn.ReLU(inplace=True),
|
|
||||||
nn.ReLU(inplace=False),
|
|
||||||
nn.Conv2d(64, 64, kernel_size=3, stride=2, padding=1, bias=False),
|
|
||||||
nn.BatchNorm2d(64),
|
|
||||||
# nn.ReLU(inplace=True),
|
|
||||||
nn.ReLU(inplace=False),
|
|
||||||
)
|
|
||||||
self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
|
|
||||||
|
|
||||||
self.layer1 = self._make_layer(block, 64, layers[0])
|
|
||||||
self.layer2 = self._make_layer(block, 128, layers[1], stride=2)
|
|
||||||
self.layer3 = self._make_layer(block, 256, layers[2], stride=2)
|
|
||||||
self.layer4 = self._make_layer(block, 512, layers[3], stride=2)
|
|
||||||
|
|
||||||
# Output Head: 128x128 Input -> 4x4 Feature Map
|
|
||||||
self.avgpool = nn.AvgPool2d(4) # Result: 1x1
|
|
||||||
|
|
||||||
# FC layer replaced by 1x1 Conv for 128-d embedding
|
|
||||||
self.fc_conv = nn.Conv2d(512 * block.expansion, embedding_size, kernel_size=1, bias=False)
|
|
||||||
self.bn_last = nn.BatchNorm2d(embedding_size)
|
|
||||||
|
|
||||||
# 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):
|
|
||||||
nn.init.constant_(m.weight, 1)
|
|
||||||
nn.init.constant_(m.bias, 0)
|
|
||||||
|
|
||||||
def _make_layer(self, block, planes, blocks, stride=1):
|
|
||||||
downsample = None
|
|
||||||
if stride != 1 or self.inplanes != planes * block.expansion:
|
|
||||||
downsample = nn.Sequential(
|
|
||||||
nn.Conv2d(self.inplanes, planes * block.expansion,
|
|
||||||
kernel_size=1, stride=stride, bias=False),
|
|
||||||
nn.BatchNorm2d(planes * block.expansion),
|
|
||||||
)
|
|
||||||
layers = []
|
|
||||||
layers.append(block(self.inplanes, planes, stride, downsample))
|
|
||||||
self.inplanes = planes * block.expansion
|
|
||||||
for _ in range(1, blocks):
|
|
||||||
layers.append(block(self.inplanes, planes))
|
|
||||||
return nn.Sequential(*layers)
|
|
||||||
|
|
||||||
def forward(self, x):
|
|
||||||
x = self.stem(x)
|
|
||||||
x = self.maxpool(x)
|
|
||||||
x = self.layer1(x)
|
|
||||||
x = self.layer2(x)
|
|
||||||
x = self.layer3(x)
|
|
||||||
x = self.layer4(x)
|
|
||||||
x = self.avgpool(x)
|
|
||||||
x = self.fc_conv(x)
|
|
||||||
x = self.bn_last(x) # Output: [N, 128, 1, 1]
|
|
||||||
return x
|
|
||||||
|
|
||||||
# --------------------------------------------------------
|
|
||||||
# ArcFace Loss Header
|
|
||||||
# --------------------------------------------------------
|
|
||||||
class ArcFace(nn.Module):
|
|
||||||
def __init__(self, in_features, out_features, s=64.0, m=0.50):
|
|
||||||
super(ArcFace, self).__init__()
|
|
||||||
self.in_features = in_features
|
|
||||||
self.out_features = out_features
|
|
||||||
self.s = s
|
|
||||||
self.m = m
|
|
||||||
self.weight = nn.Parameter(torch.FloatTensor(out_features, in_features))
|
|
||||||
nn.init.xavier_uniform_(self.weight)
|
|
||||||
|
|
||||||
def forward(self, input, label):
|
|
||||||
# Flatten [N, 128, 1, 1] -> [N, 128] for loss calculation
|
|
||||||
embedding = input.view(input.size(0), -1)
|
|
||||||
|
|
||||||
cosine = F.linear(F.normalize(embedding), F.normalize(self.weight))
|
|
||||||
|
|
||||||
# Stable implementation of ArcFace
|
|
||||||
theta = torch.acos(torch.clamp(cosine, -1.0 + 1e-7, 1.0 - 1e-7))
|
|
||||||
target_logits = torch.cos(theta + self.m)
|
|
||||||
|
|
||||||
one_hot = torch.zeros_like(cosine)
|
|
||||||
one_hot.scatter_(1, label.view(-1, 1).long(), 1)
|
|
||||||
|
|
||||||
output = one_hot * target_logits + (1.0 - one_hot) * cosine
|
|
||||||
output *= self.s
|
|
||||||
return output
|
|
||||||
|
|
||||||
def get_face_model():
|
|
||||||
return ResNetFace(Bottleneck, [3, 4, 6, 3], embedding_size=128)
|
|
||||||
@ -1,120 +0,0 @@
|
|||||||
import torch
|
|
||||||
import torch.nn as nn
|
|
||||||
import torch.optim as optim
|
|
||||||
import os
|
|
||||||
import argparse
|
|
||||||
from tqdm import tqdm
|
|
||||||
from datetime import datetime # 시간 정보를 가져오기 위해 추가
|
|
||||||
|
|
||||||
# Import our custom modules
|
|
||||||
from model import get_face_model, ArcFace
|
|
||||||
from dataset import get_face_dataloaders
|
|
||||||
|
|
||||||
def main():
|
|
||||||
# --------------------------------------------------------
|
|
||||||
# 1. Hyperparameters & Settings
|
|
||||||
# --------------------------------------------------------
|
|
||||||
parser = argparse.ArgumentParser(description='Face Recognition Training for Apache 6')
|
|
||||||
|
|
||||||
# 데이터셋 경로 (사용자 환경에 맞게 기본값 설정)
|
|
||||||
parser.add_argument('--data_dir', type=str, default='/home/cuuva/face_exp/datasets', help='Path to datasets')
|
|
||||||
|
|
||||||
# 결과 저장 최상위 경로 (여기 아래에 시간별 폴더가 생김)
|
|
||||||
parser.add_argument('--project_dir', type=str, default='./results', help='Base directory for results')
|
|
||||||
|
|
||||||
parser.add_argument('--epochs', type=int, default=20, help='Number of epochs')
|
|
||||||
parser.add_argument('--batch_size', type=int, default=64, help='Batch size')
|
|
||||||
parser.add_argument('--lr', type=float, default=0.1, help='Learning rate')
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
|
||||||
print(f"Device: {device}")
|
|
||||||
|
|
||||||
# --------------------------------------------------------
|
|
||||||
# [수정됨] 실험 디렉토리 생성 로직 (yy-mm-dd-hour-minute)
|
|
||||||
# --------------------------------------------------------
|
|
||||||
# 현재 시간 구하기
|
|
||||||
current_time = datetime.now().strftime("%y-%m-%d-%H-%M")
|
|
||||||
|
|
||||||
# 최종 저장 경로: ./results/23-12-12-15-30/
|
|
||||||
save_dir = os.path.join(args.project_dir, current_time)
|
|
||||||
|
|
||||||
# 폴더 생성
|
|
||||||
os.makedirs(save_dir, exist_ok=True)
|
|
||||||
print(f"✅ Experiment results will be saved to: {save_dir}")
|
|
||||||
|
|
||||||
# --------------------------------------------------------
|
|
||||||
# 2. Load Data
|
|
||||||
# --------------------------------------------------------
|
|
||||||
print("Loading Data...")
|
|
||||||
try:
|
|
||||||
train_loader, num_classes = get_face_dataloaders(args.data_dir, args.batch_size)
|
|
||||||
print(f"Classes (People): {num_classes}, Batch Size: {args.batch_size}")
|
|
||||||
except Exception as e:
|
|
||||||
print(f"❌ Error loading data: {e}")
|
|
||||||
return
|
|
||||||
|
|
||||||
# --------------------------------------------------------
|
|
||||||
# 3. Initialize Model & Loss
|
|
||||||
# --------------------------------------------------------
|
|
||||||
# Backbone (보드에 배포할 모델)
|
|
||||||
backbone = get_face_model().to(device)
|
|
||||||
|
|
||||||
# ArcFace Header (학습용 Loss 계산기)
|
|
||||||
metric_fc = ArcFace(in_features=128, out_features=num_classes).to(device)
|
|
||||||
|
|
||||||
# Loss
|
|
||||||
criterion = nn.CrossEntropyLoss()
|
|
||||||
|
|
||||||
# Optimizer
|
|
||||||
optimizer = optim.SGD([
|
|
||||||
{'params': backbone.parameters()},
|
|
||||||
{'params': metric_fc.parameters()}
|
|
||||||
], lr=args.lr, momentum=0.9, weight_decay=5e-4)
|
|
||||||
|
|
||||||
# Scheduler
|
|
||||||
scheduler = optim.lr_scheduler.MultiStepLR(optimizer, milestones=[8, 14, 18], gamma=0.1)
|
|
||||||
|
|
||||||
# --------------------------------------------------------
|
|
||||||
# 4. Training Loop
|
|
||||||
# --------------------------------------------------------
|
|
||||||
print("🚀 Start Training...")
|
|
||||||
|
|
||||||
for epoch in range(args.epochs):
|
|
||||||
backbone.train()
|
|
||||||
metric_fc.train()
|
|
||||||
|
|
||||||
running_loss = 0.0
|
|
||||||
pbar = tqdm(train_loader, desc=f"Epoch {epoch+1}/{args.epochs}")
|
|
||||||
|
|
||||||
for images, labels in pbar:
|
|
||||||
images, labels = images.to(device), labels.to(device)
|
|
||||||
|
|
||||||
optimizer.zero_grad()
|
|
||||||
|
|
||||||
# Forward Pass
|
|
||||||
features = backbone(images) # [N, 128, 1, 1]
|
|
||||||
outputs = metric_fc(features, labels) # [N, Num_Classes]
|
|
||||||
|
|
||||||
# Loss Calc & Backward
|
|
||||||
loss = criterion(outputs, labels)
|
|
||||||
loss.backward()
|
|
||||||
optimizer.step()
|
|
||||||
|
|
||||||
running_loss += loss.item()
|
|
||||||
pbar.set_postfix({'loss': running_loss / (pbar.n + 1)})
|
|
||||||
|
|
||||||
scheduler.step()
|
|
||||||
|
|
||||||
# [수정됨] Save Checkpoint (.pt 확장자 사용)
|
|
||||||
# 해당 실험 폴더(save_dir) 안에 저장됨
|
|
||||||
save_path = os.path.join(save_dir, f"backbone_epoch_{epoch+1}.pt")
|
|
||||||
torch.save(backbone.state_dict(), save_path)
|
|
||||||
|
|
||||||
# 마지막 에폭일 때 로그 출력
|
|
||||||
if epoch == args.epochs - 1:
|
|
||||||
print(f"🎉 Training Finished! Final model saved at: {save_path}")
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
@ -1,119 +0,0 @@
|
|||||||
import torch
|
|
||||||
import torch.nn.functional as F
|
|
||||||
from torch.utils.data import Dataset, DataLoader
|
|
||||||
from torchvision import transforms
|
|
||||||
from PIL import Image
|
|
||||||
import os
|
|
||||||
import numpy as np
|
|
||||||
|
|
||||||
# --------------------------------------------------------
|
|
||||||
# 1. LFW Dataset Loader
|
|
||||||
# --------------------------------------------------------
|
|
||||||
class LFWDataset(Dataset):
|
|
||||||
def __init__(self, lfw_dir, pairs_path, transform=None):
|
|
||||||
self.lfw_dir = lfw_dir
|
|
||||||
self.pairs_path = pairs_path
|
|
||||||
self.transform = transform
|
|
||||||
self.validation_images = self.get_lfw_paths(lfw_dir)
|
|
||||||
|
|
||||||
def get_lfw_paths(self, lfw_dir):
|
|
||||||
# pairs.txt 파싱하여 이미지 경로 쌍과 정답(issame) 리스트 생성
|
|
||||||
pairs = []
|
|
||||||
with open(self.pairs_path, 'r') as f:
|
|
||||||
lines = f.readlines()[1:] # 첫 줄(헤더) 건너뜀
|
|
||||||
|
|
||||||
for line in lines:
|
|
||||||
p = line.strip().split('\t')
|
|
||||||
|
|
||||||
if len(p) == 3: # 같은 사람 (name, img1_num, img2_num)
|
|
||||||
name = p[0]
|
|
||||||
img1 = os.path.join(lfw_dir, name, f"{name}_{int(p[1]):04d}.jpg")
|
|
||||||
img2 = os.path.join(lfw_dir, name, f"{name}_{int(p[2]):04d}.jpg")
|
|
||||||
issame = True
|
|
||||||
pairs.append((img1, img2, issame))
|
|
||||||
|
|
||||||
elif len(p) == 4: # 다른 사람 (name1, img1_num, name2, img2_num)
|
|
||||||
name1 = p[0]
|
|
||||||
img1 = os.path.join(lfw_dir, name1, f"{name1}_{int(p[1]):04d}.jpg")
|
|
||||||
name2 = p[2]
|
|
||||||
img2 = os.path.join(lfw_dir, name2, f"{name2}_{int(p[3]):04d}.jpg")
|
|
||||||
issame = False
|
|
||||||
pairs.append((img1, img2, issame))
|
|
||||||
return pairs
|
|
||||||
|
|
||||||
def __len__(self):
|
|
||||||
return len(self.validation_images)
|
|
||||||
|
|
||||||
def __getitem__(self, index):
|
|
||||||
img1_path, img2_path, issame = self.validation_images[index]
|
|
||||||
|
|
||||||
try:
|
|
||||||
img1 = Image.open(img1_path).convert('RGB')
|
|
||||||
img2 = Image.open(img2_path).convert('RGB')
|
|
||||||
except Exception as e:
|
|
||||||
# 혹시 파일이 없을 경우를 대비한 더미 (실제론 파일 확인 필요)
|
|
||||||
print(f"File Load Error: {e}")
|
|
||||||
img1 = Image.new('RGB', (128, 128))
|
|
||||||
img2 = Image.new('RGB', (128, 128))
|
|
||||||
|
|
||||||
if self.transform:
|
|
||||||
img1 = self.transform(img1)
|
|
||||||
img2 = self.transform(img2)
|
|
||||||
|
|
||||||
return img1, img2, issame
|
|
||||||
|
|
||||||
# --------------------------------------------------------
|
|
||||||
# 2. Evaluation Function
|
|
||||||
# --------------------------------------------------------
|
|
||||||
def validate_lfw(model, lfw_loader, device):
|
|
||||||
model.eval()
|
|
||||||
similarities = []
|
|
||||||
actual_issame = []
|
|
||||||
|
|
||||||
print("🔍 Validating on LFW...")
|
|
||||||
with torch.no_grad():
|
|
||||||
for img1, img2, issame in lfw_loader:
|
|
||||||
img1, img2 = img1.to(device), img2.to(device)
|
|
||||||
|
|
||||||
# Feature Extraction
|
|
||||||
feat1 = model(img1) # [B, 128, 1, 1]
|
|
||||||
feat2 = model(img2) # [B, 128, 1, 1]
|
|
||||||
|
|
||||||
# Flatten
|
|
||||||
feat1 = feat1.view(feat1.size(0), -1)
|
|
||||||
feat2 = feat2.view(feat2.size(0), -1)
|
|
||||||
|
|
||||||
# Cosine Similarity Calculation
|
|
||||||
# 128차원 벡터의 코사인 유사도 (-1 ~ 1)
|
|
||||||
cos_sim = F.cosine_similarity(feat1, feat2)
|
|
||||||
|
|
||||||
similarities.extend(cos_sim.cpu().numpy())
|
|
||||||
actual_issame.extend(issame.numpy())
|
|
||||||
|
|
||||||
similarities = np.array(similarities)
|
|
||||||
actual_issame = np.array(actual_issame)
|
|
||||||
|
|
||||||
# ----------------------------------------------------
|
|
||||||
# Best Threshold Search (단순화된 버전)
|
|
||||||
# ----------------------------------------------------
|
|
||||||
best_acc = 0.0
|
|
||||||
best_th = 0.0
|
|
||||||
|
|
||||||
# -1.0 부터 1.0 까지 0.01 단위로 Threshold를 이동하며 정확도 측정
|
|
||||||
thresholds = np.arange(-1.0, 1.0, 0.01)
|
|
||||||
|
|
||||||
for th in thresholds:
|
|
||||||
# th보다 크면 True(동일인), 작으면 False(타인) 예측
|
|
||||||
predict_issame = np.greater(similarities, th)
|
|
||||||
|
|
||||||
# 정답과 비교
|
|
||||||
true_positives = np.sum(np.logical_and(predict_issame, actual_issame))
|
|
||||||
true_negatives = np.sum(np.logical_and(np.logical_not(predict_issame), np.logical_not(actual_issame)))
|
|
||||||
|
|
||||||
acc = (true_positives + true_negatives) / len(actual_issame)
|
|
||||||
|
|
||||||
if acc > best_acc:
|
|
||||||
best_acc = acc
|
|
||||||
best_th = th
|
|
||||||
|
|
||||||
return best_acc, best_th
|
|
||||||
@ -1,38 +0,0 @@
|
|||||||
import easyocr
|
|
||||||
import cv2
|
|
||||||
from matplotlib import pyplot as plt
|
|
||||||
import time # ⬅ 추가
|
|
||||||
|
|
||||||
# 1. EasyOCR Reader 생성
|
|
||||||
reader = easyocr.Reader(['ko', 'en'], gpu=False)
|
|
||||||
|
|
||||||
# 2. 이미지 불러오기
|
|
||||||
# image_path = '/home/cuuva/다운로드/test/ocr_resized.png'
|
|
||||||
image_path = '/home/cuuva/experiment/custom_LP_detect/ocr2.png'
|
|
||||||
image = cv2.imread(image_path)
|
|
||||||
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
|
|
||||||
|
|
||||||
# ------------------------
|
|
||||||
# 3. OCR 수행 및 시간 측정
|
|
||||||
# ------------------------
|
|
||||||
start_time = time.time()
|
|
||||||
results = reader.readtext(image_rgb, detail=1)
|
|
||||||
end_time = time.time()
|
|
||||||
print(f"Inference time: {end_time - start_time:.3f} seconds")
|
|
||||||
|
|
||||||
# 4. 결과 출력 및 시각화
|
|
||||||
for (bbox, text, prob) in results:
|
|
||||||
print(f"Detected text: {text}, Confidence: {prob:.2f}")
|
|
||||||
|
|
||||||
# 바운딩 박스
|
|
||||||
top_left = tuple(map(int, bbox[0]))
|
|
||||||
bottom_right = tuple(map(int, bbox[2]))
|
|
||||||
cv2.rectangle(image_rgb, top_left, bottom_right, (0, 255, 0), 2)
|
|
||||||
cv2.putText(image_rgb, text, (top_left[0], top_left[1]-10),
|
|
||||||
cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2)
|
|
||||||
|
|
||||||
# 5. 시각화
|
|
||||||
plt.figure(figsize=(10,6))
|
|
||||||
plt.imshow(image_rgb)
|
|
||||||
plt.axis('off')
|
|
||||||
plt.show()
|
|
||||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,94 @@
|
|||||||
|
import os
|
||||||
|
import glob
|
||||||
|
from tqdm.notebook import tqdm # 주피터 노트북용 진행바
|
||||||
|
|
||||||
|
# ==========================================
|
||||||
|
# 1. 절대 경로 설정 (수정된 부분)
|
||||||
|
# ==========================================
|
||||||
|
# 사용자 홈 디렉토리(/home/cuuva)를 포함한 전체 경로를 입력합니다.
|
||||||
|
SRC_ROOT = '/home/cuuva/git/Detection_Experiment/datasets/fashionpedia_yolo/labels_all_bak'
|
||||||
|
DST_ROOT = '/home/cuuva/git/Detection_Experiment/datasets/fashionpedia_yolo/labels_reduced'
|
||||||
|
|
||||||
|
# ==========================================
|
||||||
|
# 2. 클래스 매핑 규칙 (Old ID -> New ID)
|
||||||
|
# ==========================================
|
||||||
|
# 0(shirt), 1(top), 2(sweater) -> 0 (shirt)
|
||||||
|
# 3(cardigan), 4(jacket) -> 1 (jacket)
|
||||||
|
# 6(pants) -> 2 (pants)
|
||||||
|
# 13(glasses) -> 3 (glasses)
|
||||||
|
class_mapping = {
|
||||||
|
0: 0, 1: 0, 2: 0,
|
||||||
|
3: 1, 4: 1,
|
||||||
|
6: 2,
|
||||||
|
13: 3
|
||||||
|
}
|
||||||
|
|
||||||
|
print(f"원본 경로: {SRC_ROOT}")
|
||||||
|
print(f"저장 경로: {DST_ROOT}")
|
||||||
|
print("-" * 30)
|
||||||
|
|
||||||
|
# ==========================================
|
||||||
|
# 3. 데이터 변환 로직
|
||||||
|
# ==========================================
|
||||||
|
def process_yolo_labels(src_root, dst_root, mapping):
|
||||||
|
subsets = ['train', 'val']
|
||||||
|
|
||||||
|
total_files = 0
|
||||||
|
total_objects_kept = 0
|
||||||
|
|
||||||
|
for subset in subsets:
|
||||||
|
src_dir = os.path.join(src_root, subset)
|
||||||
|
dst_dir = os.path.join(dst_root, subset)
|
||||||
|
|
||||||
|
# 소스 디렉토리 존재 확인
|
||||||
|
if not os.path.exists(src_dir):
|
||||||
|
print(f"⚠️ 에러: 소스 폴더를 찾을 수 없습니다 -> {src_dir}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 타겟 디렉토리 생성
|
||||||
|
os.makedirs(dst_dir, exist_ok=True)
|
||||||
|
|
||||||
|
# 파일 목록 로드
|
||||||
|
txt_files = glob.glob(os.path.join(src_dir, '*.txt'))
|
||||||
|
total_files += len(txt_files)
|
||||||
|
|
||||||
|
print(f"🚀 Processing [{subset}]: {len(txt_files)} files found.")
|
||||||
|
|
||||||
|
# 변환 시작
|
||||||
|
for file_path in tqdm(txt_files, desc=f"{subset} Converting"):
|
||||||
|
file_name = os.path.basename(file_path)
|
||||||
|
dst_path = os.path.join(dst_dir, file_name)
|
||||||
|
|
||||||
|
new_lines = []
|
||||||
|
|
||||||
|
with open(file_path, 'r') as f:
|
||||||
|
lines = f.readlines()
|
||||||
|
|
||||||
|
for line in lines:
|
||||||
|
parts = line.strip().split()
|
||||||
|
if not parts: continue
|
||||||
|
|
||||||
|
old_cls = int(parts[0])
|
||||||
|
coords = parts[1:] # x, y, w, h
|
||||||
|
|
||||||
|
# 매핑 규칙에 있는 클래스만 남김
|
||||||
|
if old_cls in mapping:
|
||||||
|
new_cls = mapping[old_cls]
|
||||||
|
new_line = f"{new_cls} {' '.join(coords)}\n"
|
||||||
|
new_lines.append(new_line)
|
||||||
|
total_objects_kept += 1
|
||||||
|
|
||||||
|
# 파일 쓰기 (빈 파일이라도 생성하여 구조 유지)
|
||||||
|
with open(dst_path, 'w') as f:
|
||||||
|
f.writelines(new_lines)
|
||||||
|
|
||||||
|
return total_files, total_objects_kept
|
||||||
|
|
||||||
|
# 실행
|
||||||
|
processed_cnt, kept_cnt = process_yolo_labels(SRC_ROOT, DST_ROOT, class_mapping)
|
||||||
|
|
||||||
|
print("="*30)
|
||||||
|
print("✅ 변환 완료")
|
||||||
|
print(f"총 처리된 파일: {processed_cnt}개")
|
||||||
|
print(f"남은 객체 수: {kept_cnt}개")
|
||||||
|
print(f"저장된 위치: {DST_ROOT}")
|
||||||
@ -0,0 +1,106 @@
|
|||||||
|
task: detect
|
||||||
|
mode: train
|
||||||
|
model: yolov8m.pt
|
||||||
|
data: /home/cuuva/git/Detection_Experiment/datasets/fashionpedia_yolo/fashionpedia_custom.yaml
|
||||||
|
epochs: 500
|
||||||
|
time: null
|
||||||
|
patience: 50
|
||||||
|
batch: -1
|
||||||
|
imgsz: 640
|
||||||
|
save: true
|
||||||
|
save_period: -1
|
||||||
|
cache: false
|
||||||
|
device: '0'
|
||||||
|
workers: 8
|
||||||
|
project: fashionpedia_exp
|
||||||
|
name: yolov8m_fashion_4class
|
||||||
|
exist_ok: false
|
||||||
|
pretrained: true
|
||||||
|
optimizer: AdamW
|
||||||
|
verbose: true
|
||||||
|
seed: 0
|
||||||
|
deterministic: true
|
||||||
|
single_cls: false
|
||||||
|
rect: false
|
||||||
|
cos_lr: false
|
||||||
|
close_mosaic: 10
|
||||||
|
resume: false
|
||||||
|
amp: true
|
||||||
|
fraction: 1.0
|
||||||
|
profile: false
|
||||||
|
freeze: null
|
||||||
|
multi_scale: false
|
||||||
|
compile: false
|
||||||
|
overlap_mask: true
|
||||||
|
mask_ratio: 4
|
||||||
|
dropout: 0.0
|
||||||
|
val: true
|
||||||
|
split: val
|
||||||
|
save_json: false
|
||||||
|
conf: null
|
||||||
|
iou: 0.7
|
||||||
|
max_det: 300
|
||||||
|
half: false
|
||||||
|
dnn: false
|
||||||
|
plots: true
|
||||||
|
source: null
|
||||||
|
vid_stride: 1
|
||||||
|
stream_buffer: false
|
||||||
|
visualize: false
|
||||||
|
augment: false
|
||||||
|
agnostic_nms: false
|
||||||
|
classes: null
|
||||||
|
retina_masks: false
|
||||||
|
embed: null
|
||||||
|
show: false
|
||||||
|
save_frames: false
|
||||||
|
save_txt: false
|
||||||
|
save_conf: false
|
||||||
|
save_crop: false
|
||||||
|
show_labels: true
|
||||||
|
show_conf: true
|
||||||
|
show_boxes: true
|
||||||
|
line_width: null
|
||||||
|
format: torchscript
|
||||||
|
keras: false
|
||||||
|
optimize: false
|
||||||
|
int8: false
|
||||||
|
dynamic: false
|
||||||
|
simplify: true
|
||||||
|
opset: null
|
||||||
|
workspace: null
|
||||||
|
nms: false
|
||||||
|
lr0: 0.001
|
||||||
|
lrf: 0.01
|
||||||
|
momentum: 0.937
|
||||||
|
weight_decay: 0.0005
|
||||||
|
warmup_epochs: 3.0
|
||||||
|
warmup_momentum: 0.8
|
||||||
|
warmup_bias_lr: 0.1
|
||||||
|
box: 7.5
|
||||||
|
cls: 0.5
|
||||||
|
dfl: 1.5
|
||||||
|
pose: 12.0
|
||||||
|
kobj: 1.0
|
||||||
|
nbs: 64
|
||||||
|
hsv_h: 0.015
|
||||||
|
hsv_s: 0.7
|
||||||
|
hsv_v: 0.4
|
||||||
|
degrees: 0.0
|
||||||
|
translate: 0.1
|
||||||
|
scale: 0.5
|
||||||
|
shear: 0.0
|
||||||
|
perspective: 0.0
|
||||||
|
flipud: 0.0
|
||||||
|
fliplr: 0.5
|
||||||
|
bgr: 0.0
|
||||||
|
mosaic: 1.0
|
||||||
|
mixup: 0.0
|
||||||
|
cutmix: 0.0
|
||||||
|
copy_paste: 0.0
|
||||||
|
copy_paste_mode: flip
|
||||||
|
auto_augment: randaugment
|
||||||
|
erasing: 0.4
|
||||||
|
cfg: null
|
||||||
|
tracker: botsort.yaml
|
||||||
|
save_dir: /home/cuuva/git/Detection_Experiment/fashion_yolo/fashionpedia_exp/yolov8m_fashion_4class
|
||||||
|
@ -0,0 +1,106 @@
|
|||||||
|
task: detect
|
||||||
|
mode: train
|
||||||
|
model: yolov8m.pt
|
||||||
|
data: /home/cuuva/git/Detection_Experiment/fashion_yolo/finetuning_exp/finetuning_dataset.yaml
|
||||||
|
epochs: 200
|
||||||
|
time: null
|
||||||
|
patience: 50
|
||||||
|
batch: -1
|
||||||
|
imgsz: 640
|
||||||
|
save: true
|
||||||
|
save_period: -1
|
||||||
|
cache: false
|
||||||
|
device: '0'
|
||||||
|
workers: 8
|
||||||
|
project: finetuned_exp
|
||||||
|
name: yolov8m_finetuned_16class
|
||||||
|
exist_ok: false
|
||||||
|
pretrained: true
|
||||||
|
optimizer: AdamW
|
||||||
|
verbose: true
|
||||||
|
seed: 0
|
||||||
|
deterministic: true
|
||||||
|
single_cls: false
|
||||||
|
rect: false
|
||||||
|
cos_lr: false
|
||||||
|
close_mosaic: 10
|
||||||
|
resume: false
|
||||||
|
amp: true
|
||||||
|
fraction: 1.0
|
||||||
|
profile: false
|
||||||
|
freeze: null
|
||||||
|
multi_scale: false
|
||||||
|
compile: false
|
||||||
|
overlap_mask: true
|
||||||
|
mask_ratio: 4
|
||||||
|
dropout: 0.0
|
||||||
|
val: true
|
||||||
|
split: val
|
||||||
|
save_json: false
|
||||||
|
conf: null
|
||||||
|
iou: 0.7
|
||||||
|
max_det: 300
|
||||||
|
half: false
|
||||||
|
dnn: false
|
||||||
|
plots: true
|
||||||
|
source: null
|
||||||
|
vid_stride: 1
|
||||||
|
stream_buffer: false
|
||||||
|
visualize: false
|
||||||
|
augment: false
|
||||||
|
agnostic_nms: false
|
||||||
|
classes: null
|
||||||
|
retina_masks: false
|
||||||
|
embed: null
|
||||||
|
show: false
|
||||||
|
save_frames: false
|
||||||
|
save_txt: false
|
||||||
|
save_conf: false
|
||||||
|
save_crop: false
|
||||||
|
show_labels: true
|
||||||
|
show_conf: true
|
||||||
|
show_boxes: true
|
||||||
|
line_width: null
|
||||||
|
format: torchscript
|
||||||
|
keras: false
|
||||||
|
optimize: false
|
||||||
|
int8: false
|
||||||
|
dynamic: false
|
||||||
|
simplify: true
|
||||||
|
opset: null
|
||||||
|
workspace: null
|
||||||
|
nms: false
|
||||||
|
lr0: 0.001
|
||||||
|
lrf: 0.01
|
||||||
|
momentum: 0.937
|
||||||
|
weight_decay: 0.0005
|
||||||
|
warmup_epochs: 3.0
|
||||||
|
warmup_momentum: 0.8
|
||||||
|
warmup_bias_lr: 0.1
|
||||||
|
box: 7.5
|
||||||
|
cls: 0.5
|
||||||
|
dfl: 1.5
|
||||||
|
pose: 12.0
|
||||||
|
kobj: 1.0
|
||||||
|
nbs: 64
|
||||||
|
hsv_h: 0.015
|
||||||
|
hsv_s: 0.7
|
||||||
|
hsv_v: 0.4
|
||||||
|
degrees: 0.0
|
||||||
|
translate: 0.1
|
||||||
|
scale: 0.5
|
||||||
|
shear: 0.0
|
||||||
|
perspective: 0.0
|
||||||
|
flipud: 0.0
|
||||||
|
fliplr: 0.5
|
||||||
|
bgr: 0.0
|
||||||
|
mosaic: 1.0
|
||||||
|
mixup: 0.0
|
||||||
|
cutmix: 0.0
|
||||||
|
copy_paste: 0.0
|
||||||
|
copy_paste_mode: flip
|
||||||
|
auto_augment: randaugment
|
||||||
|
erasing: 0.4
|
||||||
|
cfg: null
|
||||||
|
tracker: botsort.yaml
|
||||||
|
save_dir: /home/cuuva/git/Detection_Experiment/fashion_yolo/finetuning_exp/finetuned_exp/yolov8m_finetuned_16class
|
||||||
|
@ -0,0 +1,106 @@
|
|||||||
|
task: detect
|
||||||
|
mode: train
|
||||||
|
model: /home/cuuva/git/Detection_Experiment/fashion_yolo/fashionpedia_exp/yolov8m_fashion_final/weights/best_fashion_16class.pt
|
||||||
|
data: /home/cuuva/git/Detection_Experiment/fashion_yolo/finetuning_exp/finetuning_dataset.yaml
|
||||||
|
epochs: 200
|
||||||
|
time: null
|
||||||
|
patience: 50
|
||||||
|
batch: -1
|
||||||
|
imgsz: 640
|
||||||
|
save: true
|
||||||
|
save_period: -1
|
||||||
|
cache: false
|
||||||
|
device: '0'
|
||||||
|
workers: 8
|
||||||
|
project: finetuned_exp
|
||||||
|
name: yolov8m_finetuned_16class2
|
||||||
|
exist_ok: false
|
||||||
|
pretrained: true
|
||||||
|
optimizer: AdamW
|
||||||
|
verbose: true
|
||||||
|
seed: 0
|
||||||
|
deterministic: true
|
||||||
|
single_cls: false
|
||||||
|
rect: false
|
||||||
|
cos_lr: false
|
||||||
|
close_mosaic: 10
|
||||||
|
resume: false
|
||||||
|
amp: true
|
||||||
|
fraction: 1.0
|
||||||
|
profile: false
|
||||||
|
freeze: null
|
||||||
|
multi_scale: false
|
||||||
|
compile: false
|
||||||
|
overlap_mask: true
|
||||||
|
mask_ratio: 4
|
||||||
|
dropout: 0.0
|
||||||
|
val: true
|
||||||
|
split: val
|
||||||
|
save_json: false
|
||||||
|
conf: null
|
||||||
|
iou: 0.7
|
||||||
|
max_det: 300
|
||||||
|
half: false
|
||||||
|
dnn: false
|
||||||
|
plots: true
|
||||||
|
source: null
|
||||||
|
vid_stride: 1
|
||||||
|
stream_buffer: false
|
||||||
|
visualize: false
|
||||||
|
augment: false
|
||||||
|
agnostic_nms: false
|
||||||
|
classes: null
|
||||||
|
retina_masks: false
|
||||||
|
embed: null
|
||||||
|
show: false
|
||||||
|
save_frames: false
|
||||||
|
save_txt: false
|
||||||
|
save_conf: false
|
||||||
|
save_crop: false
|
||||||
|
show_labels: true
|
||||||
|
show_conf: true
|
||||||
|
show_boxes: true
|
||||||
|
line_width: null
|
||||||
|
format: torchscript
|
||||||
|
keras: false
|
||||||
|
optimize: false
|
||||||
|
int8: false
|
||||||
|
dynamic: false
|
||||||
|
simplify: true
|
||||||
|
opset: null
|
||||||
|
workspace: null
|
||||||
|
nms: false
|
||||||
|
lr0: 0.001
|
||||||
|
lrf: 0.01
|
||||||
|
momentum: 0.937
|
||||||
|
weight_decay: 0.0005
|
||||||
|
warmup_epochs: 3.0
|
||||||
|
warmup_momentum: 0.8
|
||||||
|
warmup_bias_lr: 0.1
|
||||||
|
box: 7.5
|
||||||
|
cls: 0.5
|
||||||
|
dfl: 1.5
|
||||||
|
pose: 12.0
|
||||||
|
kobj: 1.0
|
||||||
|
nbs: 64
|
||||||
|
hsv_h: 0.015
|
||||||
|
hsv_s: 0.7
|
||||||
|
hsv_v: 0.4
|
||||||
|
degrees: 0.0
|
||||||
|
translate: 0.1
|
||||||
|
scale: 0.5
|
||||||
|
shear: 0.0
|
||||||
|
perspective: 0.0
|
||||||
|
flipud: 0.0
|
||||||
|
fliplr: 0.5
|
||||||
|
bgr: 0.0
|
||||||
|
mosaic: 1.0
|
||||||
|
mixup: 0.0
|
||||||
|
cutmix: 0.0
|
||||||
|
copy_paste: 0.0
|
||||||
|
copy_paste_mode: flip
|
||||||
|
auto_augment: randaugment
|
||||||
|
erasing: 0.4
|
||||||
|
cfg: null
|
||||||
|
tracker: botsort.yaml
|
||||||
|
save_dir: /home/cuuva/git/Detection_Experiment/fashion_yolo/finetuning_exp/finetuned_exp/yolov8m_finetuned_16class2
|
||||||
|
@ -0,0 +1,106 @@
|
|||||||
|
task: detect
|
||||||
|
mode: train
|
||||||
|
model: yolov8m.pt
|
||||||
|
data: /home/cuuva/git/Detection_Experiment/fashion_yolo/finetuning_exp/finetuning_dataset.yaml
|
||||||
|
epochs: 200
|
||||||
|
time: null
|
||||||
|
patience: 50
|
||||||
|
batch: -1
|
||||||
|
imgsz: 640
|
||||||
|
save: true
|
||||||
|
save_period: -1
|
||||||
|
cache: false
|
||||||
|
device: '0'
|
||||||
|
workers: 8
|
||||||
|
project: finetuned_exp
|
||||||
|
name: yolov8m_finetuned_16class2
|
||||||
|
exist_ok: false
|
||||||
|
pretrained: true
|
||||||
|
optimizer: AdamW
|
||||||
|
verbose: true
|
||||||
|
seed: 0
|
||||||
|
deterministic: true
|
||||||
|
single_cls: false
|
||||||
|
rect: false
|
||||||
|
cos_lr: false
|
||||||
|
close_mosaic: 10
|
||||||
|
resume: false
|
||||||
|
amp: true
|
||||||
|
fraction: 1.0
|
||||||
|
profile: false
|
||||||
|
freeze: null
|
||||||
|
multi_scale: false
|
||||||
|
compile: false
|
||||||
|
overlap_mask: true
|
||||||
|
mask_ratio: 4
|
||||||
|
dropout: 0.0
|
||||||
|
val: true
|
||||||
|
split: val
|
||||||
|
save_json: false
|
||||||
|
conf: null
|
||||||
|
iou: 0.7
|
||||||
|
max_det: 300
|
||||||
|
half: false
|
||||||
|
dnn: false
|
||||||
|
plots: true
|
||||||
|
source: null
|
||||||
|
vid_stride: 1
|
||||||
|
stream_buffer: false
|
||||||
|
visualize: false
|
||||||
|
augment: false
|
||||||
|
agnostic_nms: false
|
||||||
|
classes: null
|
||||||
|
retina_masks: false
|
||||||
|
embed: null
|
||||||
|
show: false
|
||||||
|
save_frames: false
|
||||||
|
save_txt: false
|
||||||
|
save_conf: false
|
||||||
|
save_crop: false
|
||||||
|
show_labels: true
|
||||||
|
show_conf: true
|
||||||
|
show_boxes: true
|
||||||
|
line_width: null
|
||||||
|
format: torchscript
|
||||||
|
keras: false
|
||||||
|
optimize: false
|
||||||
|
int8: false
|
||||||
|
dynamic: false
|
||||||
|
simplify: true
|
||||||
|
opset: null
|
||||||
|
workspace: null
|
||||||
|
nms: false
|
||||||
|
lr0: 0.001
|
||||||
|
lrf: 0.01
|
||||||
|
momentum: 0.937
|
||||||
|
weight_decay: 0.0005
|
||||||
|
warmup_epochs: 3.0
|
||||||
|
warmup_momentum: 0.8
|
||||||
|
warmup_bias_lr: 0.1
|
||||||
|
box: 7.5
|
||||||
|
cls: 0.5
|
||||||
|
dfl: 1.5
|
||||||
|
pose: 12.0
|
||||||
|
kobj: 1.0
|
||||||
|
nbs: 64
|
||||||
|
hsv_h: 0.015
|
||||||
|
hsv_s: 0.7
|
||||||
|
hsv_v: 0.4
|
||||||
|
degrees: 0.0
|
||||||
|
translate: 0.1
|
||||||
|
scale: 0.5
|
||||||
|
shear: 0.0
|
||||||
|
perspective: 0.0
|
||||||
|
flipud: 0.0
|
||||||
|
fliplr: 0.5
|
||||||
|
bgr: 0.0
|
||||||
|
mosaic: 1.0
|
||||||
|
mixup: 0.0
|
||||||
|
cutmix: 0.0
|
||||||
|
copy_paste: 0.0
|
||||||
|
copy_paste_mode: flip
|
||||||
|
auto_augment: randaugment
|
||||||
|
erasing: 0.4
|
||||||
|
cfg: null
|
||||||
|
tracker: botsort.yaml
|
||||||
|
save_dir: /home/cuuva/git/Detection_Experiment/fashion_yolo/finetuning_exp/finetuned_exp/yolov8m_finetuned_16class2
|
||||||
|
@ -0,0 +1,106 @@
|
|||||||
|
task: detect
|
||||||
|
mode: train
|
||||||
|
model: yolov8m.pt
|
||||||
|
data: /home/cuuva/git/Detection_Experiment/fashion_yolo/finetuning_exp/finetuning_dataset.yaml
|
||||||
|
epochs: 200
|
||||||
|
time: null
|
||||||
|
patience: 50
|
||||||
|
batch: -1
|
||||||
|
imgsz: 640
|
||||||
|
save: true
|
||||||
|
save_period: -1
|
||||||
|
cache: false
|
||||||
|
device: '0'
|
||||||
|
workers: 8
|
||||||
|
project: finetuned_exp
|
||||||
|
name: yolov8m_finetuned_4class
|
||||||
|
exist_ok: false
|
||||||
|
pretrained: true
|
||||||
|
optimizer: AdamW
|
||||||
|
verbose: true
|
||||||
|
seed: 0
|
||||||
|
deterministic: true
|
||||||
|
single_cls: false
|
||||||
|
rect: false
|
||||||
|
cos_lr: false
|
||||||
|
close_mosaic: 10
|
||||||
|
resume: false
|
||||||
|
amp: true
|
||||||
|
fraction: 1.0
|
||||||
|
profile: false
|
||||||
|
freeze: null
|
||||||
|
multi_scale: false
|
||||||
|
compile: false
|
||||||
|
overlap_mask: true
|
||||||
|
mask_ratio: 4
|
||||||
|
dropout: 0.0
|
||||||
|
val: true
|
||||||
|
split: val
|
||||||
|
save_json: false
|
||||||
|
conf: null
|
||||||
|
iou: 0.7
|
||||||
|
max_det: 300
|
||||||
|
half: false
|
||||||
|
dnn: false
|
||||||
|
plots: true
|
||||||
|
source: null
|
||||||
|
vid_stride: 1
|
||||||
|
stream_buffer: false
|
||||||
|
visualize: false
|
||||||
|
augment: false
|
||||||
|
agnostic_nms: false
|
||||||
|
classes: null
|
||||||
|
retina_masks: false
|
||||||
|
embed: null
|
||||||
|
show: false
|
||||||
|
save_frames: false
|
||||||
|
save_txt: false
|
||||||
|
save_conf: false
|
||||||
|
save_crop: false
|
||||||
|
show_labels: true
|
||||||
|
show_conf: true
|
||||||
|
show_boxes: true
|
||||||
|
line_width: null
|
||||||
|
format: torchscript
|
||||||
|
keras: false
|
||||||
|
optimize: false
|
||||||
|
int8: false
|
||||||
|
dynamic: false
|
||||||
|
simplify: true
|
||||||
|
opset: null
|
||||||
|
workspace: null
|
||||||
|
nms: false
|
||||||
|
lr0: 0.001
|
||||||
|
lrf: 0.01
|
||||||
|
momentum: 0.937
|
||||||
|
weight_decay: 0.0005
|
||||||
|
warmup_epochs: 3.0
|
||||||
|
warmup_momentum: 0.8
|
||||||
|
warmup_bias_lr: 0.1
|
||||||
|
box: 7.5
|
||||||
|
cls: 0.5
|
||||||
|
dfl: 1.5
|
||||||
|
pose: 12.0
|
||||||
|
kobj: 1.0
|
||||||
|
nbs: 64
|
||||||
|
hsv_h: 0.015
|
||||||
|
hsv_s: 0.7
|
||||||
|
hsv_v: 0.4
|
||||||
|
degrees: 0.0
|
||||||
|
translate: 0.1
|
||||||
|
scale: 0.5
|
||||||
|
shear: 0.0
|
||||||
|
perspective: 0.0
|
||||||
|
flipud: 0.0
|
||||||
|
fliplr: 0.5
|
||||||
|
bgr: 0.0
|
||||||
|
mosaic: 1.0
|
||||||
|
mixup: 0.0
|
||||||
|
cutmix: 0.0
|
||||||
|
copy_paste: 0.0
|
||||||
|
copy_paste_mode: flip
|
||||||
|
auto_augment: randaugment
|
||||||
|
erasing: 0.4
|
||||||
|
cfg: null
|
||||||
|
tracker: botsort.yaml
|
||||||
|
save_dir: /home/cuuva/git/Detection_Experiment/fashion_yolo/finetuning_exp/finetuned_exp/yolov8m_finetuned_4class
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
# path: /home/cuuva/git/Detection_Experiment/datasets/finetune_dataset/
|
||||||
|
|
||||||
|
train: /home/cuuva/git/Detection_Experiment/datasets/finetune_dataset/train/images/
|
||||||
|
val: /home/cuuva/git/Detection_Experiment/datasets/finetune_dataset/val/images/
|
||||||
|
|
||||||
|
# Classes
|
||||||
|
nc: 16 # (18개 -> 16개로 감소)
|
||||||
|
|
||||||
|
names:
|
||||||
|
0: shirt(blouse)
|
||||||
|
1: t-shirt(sweatshirt)
|
||||||
|
2: sweater
|
||||||
|
3: cardigan
|
||||||
|
4: jacket
|
||||||
|
5: vest
|
||||||
|
6: pants
|
||||||
|
7: shorts
|
||||||
|
8: skirt
|
||||||
|
9: coat
|
||||||
|
10: dress # (dress + jumpsuit + cape)
|
||||||
|
11: glasses # (Old 13)
|
||||||
|
12: hat # (Old 14)
|
||||||
|
13: shoe # (Old 15)
|
||||||
|
14: bag, wallet # (Old 16)
|
||||||
|
15: scarf # (Old 17)
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
from ultralytics import YOLO
|
||||||
|
|
||||||
|
# 1. 모델 로드 (YOLOv8m 사용)
|
||||||
|
# model = YOLO('yolov8m.pt')
|
||||||
|
model = YOLO("/home/cuuva/git/Detection_Experiment/fashion_yolo/fashionpedia_exp/yolov8m_fashion_final/weights/best_fashion_16class.pt")
|
||||||
|
|
||||||
|
train_results = model.train(
|
||||||
|
data="/home/cuuva/git/Detection_Experiment/fashion_yolo/finetuning_exp/finetuning_dataset.yaml",
|
||||||
|
epochs=200,
|
||||||
|
imgsz=640,
|
||||||
|
batch=-1,
|
||||||
|
device="cuda",
|
||||||
|
optimizer='AdamW',
|
||||||
|
lr0=0.001,
|
||||||
|
patience=50,
|
||||||
|
project='finetuned_exp',
|
||||||
|
name='yolov8m_finetuned_16class',
|
||||||
|
)
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue