File size: 6,250 Bytes
227e832
ef4706e
227e832
ef4706e
 
227e832
ef4706e
 
227e832
ef4706e
227e832
 
ef4706e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227e832
ef4706e
 
 
227e832
ef4706e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227e832
ef4706e
 
227e832
ef4706e
 
 
 
 
 
227e832
 
 
 
 
 
 
 
 
ef4706e
227e832
 
 
ef4706e
227e832
 
ef4706e
227e832
 
 
 
 
 
ef4706e
227e832
ef4706e
227e832
 
 
 
 
 
 
 
ef4706e
227e832
 
 
ef4706e
227e832
 
 
ef4706e
227e832
ef4706e
227e832
 
 
 
 
 
 
 
 
 
 
ef4706e
227e832
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ef4706e
227e832
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ef4706e
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
import gradio as gr
import torch
import os
from torch.utils.data import Dataset, DataLoader
from torchvision import transforms
from PIL import Image
import xml.etree.ElementTree as ET
import torch.optim as optim
from torch import nn

# Your model training and evaluation functions (already defined in your previous code)
# Define the custom dataset
class FaceMaskDataset(Dataset):
    def __init__(self, images_dir, annotations_dir, transform=None, resize=(800, 800)):
        self.images_dir = images_dir
        self.annotations_dir = annotations_dir
        self.transform = transform
        self.resize = resize
        self.image_files = os.listdir(images_dir)

    def __len__(self):
        return len(self.image_files)

    def __getitem__(self, idx):
        image_path = os.path.join(self.images_dir, self.image_files[idx])
        image = Image.open(image_path).convert("RGB")
        image = image.resize(self.resize)

        annotation_path = os.path.join(self.annotations_dir, self.image_files[idx].replace(".jpg", ".xml").replace(".png", ".xml"))
        
        if not os.path.exists(annotation_path):
            print(f"Warning: Annotation file {annotation_path} does not exist. Skipping image {self.image_files[idx]}.")
            return None, None  # Return None if annotation is missing
        
        boxes, labels = self.load_annotations(annotation_path)
        if boxes is None or labels is None:
            return None, None  # Skip if annotations are invalid

        target = {'boxes': boxes, 'labels': labels}

        if self.transform:
            image = self.transform(image)

        return image, target

    def load_annotations(self, annotation_path):
        tree = ET.parse(annotation_path)
        root = tree.getroot()

        boxes = []
        labels = []
        for obj in root.iter('object'):
            label = obj.find('name').text
            bndbox = obj.find('bndbox')
            xmin = float(bndbox.find('xmin').text)
            ymin = float(bndbox.find('ymin').text)
            xmax = float(bndbox.find('xmax').text)
            ymax = float(bndbox.find('ymax').text)
            boxes.append([xmin, ymin, xmax, ymax])
            labels.append(1 if label == "mask" else 0)  # "mask" = 1, "no_mask" = 0

        if len(boxes) == 0 or len(labels) == 0:
            return None, None  # If no boxes or labels, return None

        boxes = torch.as_tensor(boxes, dtype=torch.float32)
        labels = torch.tensor(labels, dtype=torch.int64)

        return boxes, labels

# Model Training Loop (referred to from previous code)
def train_model(model, train_loader, val_loader, optimizer, num_epochs=10):
    for epoch in range(num_epochs):
        # Training loop
        running_loss = 0.0
        model.train()
        for images, targets in train_loader:
            if images is None or targets is None:
                continue  # Skip invalid images/annotations

            # Move data to device
            images = [image.to(device) for image in images]
            targets = [{k: v.to(device) for k, v in t.items()} for t in targets]

            optimizer.zero_grad()
            loss_dict = model(images, targets)

            # Calculate total loss
            total_loss = sum(loss for loss in loss_dict.values())
            total_loss.backward()
            optimizer.step()

            running_loss += total_loss.item()

        print(f"Epoch {epoch+1}/{num_epochs}, Loss: {running_loss / len(train_loader)}")

        # Evaluate after every epoch
        val_loss = evaluate_model(model, val_loader)
        print(f"Validation Loss: {val_loss}")

# Validation function
def evaluate_model(model, val_loader):
    model.eval()
    running_loss = 0.0
    with torch.no_grad():
        for images, targets in val_loader:
            if images is None or targets is None:
                continue  # Skip invalid data

            # Move data to device
            images = [image.to(device) for image in images]
            targets = [{k: v.to(device) for k, v in t.items()} for t in targets]

            loss_dict = model(images, targets)

            # Calculate total loss
            total_loss = sum(loss for loss in loss_dict.values())
            running_loss += total_loss.item()

    return running_loss / len(val_loader)

# Function to upload dataset and start training
def train_on_uploaded_data(train_data, val_data):
    # Save the uploaded dataset (files)
    train_data_path = "train_data.zip"
    val_data_path = "val_data.zip"
    
    # Unzip and prepare directories (assuming you upload zip files for simplicity)
    with open(train_data.name, 'wb') as f:
        f.write(train_data.read())
    with open(val_data.name, 'wb') as f:
        f.write(val_data.read())

    # Extract zip files
    os.system(f"unzip {train_data_path} -d ./train/")
    os.system(f"unzip {val_data_path} -d ./val/")

    # Load datasets
    train_dataset = FaceMaskDataset(
        images_dir="train/images", 
        annotations_dir="train/annotations", 
        transform=transforms.Compose([transforms.Resize((224, 224)), transforms.ToTensor()])
    )
    val_dataset = FaceMaskDataset(
        images_dir="val/images", 
        annotations_dir="val/annotations", 
        transform=transforms.Compose([transforms.Resize((224, 224)), transforms.ToTensor()])
    )
    
    # Dataloaders
    train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True, collate_fn=collate_fn)
    val_loader = DataLoader(val_dataset, batch_size=32, shuffle=False, collate_fn=collate_fn)

    # Train the model
    model = get_model(num_classes=2)  # Assuming you have a model function
    model.to(device)
    optimizer = optim.SGD(model.parameters(), lr=0.005, momentum=0.9, weight_decay=0.0005)

    # Train the model and return feedback
    train_model(model, train_loader, val_loader, optimizer, num_epochs=10)

    return "Training completed and model saved."

# Create Gradio Interface
iface = gr.Interface(
    fn=train_on_uploaded_data,
    inputs=[
        gr.File(label="Upload Train Dataset (ZIP)"),
        gr.File(label="Upload Validation Dataset (ZIP)")
    ],
    outputs=gr.Textbox(label="Training Status"),
    live=True
)

# Launch Gradio interface
iface.launch()