Tanishq commited on
Commit
2972f68
1 Parent(s): 1c7c760

Upload 7 files

Browse files
Files changed (7) hide show
  1. config.py +23 -0
  2. dataset.py +39 -0
  3. model.py +151 -0
  4. requirements.txt +7 -0
  5. train.py +144 -0
  6. uploads/31572.jpg +0 -0
  7. utils.py +21 -0
config.py ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from albumentations.pytorch import ToTensorV2
3
+ import albumentations as A
4
+
5
+ # DEVICE = "cpu"
6
+ DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
7
+ TRAIN_DIR = "images/train"
8
+ VAL_DIR = "images/validation"
9
+ LEARNING_RATE = 2e-3
10
+ BATCH_SIZE = 128
11
+ NUM_WORKERS = 2
12
+ NUM_EPOCHS = 100
13
+ LOAD_MODEL = True
14
+ SAVE_MODEL = True
15
+ CHECKPOINT = "face_emotion.pth.tar"
16
+
17
+ transform = A.Compose(
18
+ [
19
+ A.Resize(height=48, width=48),
20
+ A.Normalize(mean=[0.5], std=[0.5], max_pixel_value=255.0, ),
21
+ ToTensorV2(),
22
+ ]
23
+ )
dataset.py ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import numpy as np
3
+ import torch
4
+ from PIL import Image
5
+ from torch.utils.data import Dataset
6
+ import config
7
+
8
+
9
+ class EmotionDataset(Dataset):
10
+ def __init__(self, root_dir, transform=config.transform):
11
+ self.root_dir = root_dir
12
+ self.transform = transform
13
+ self.classes = sorted(os.listdir(root_dir))
14
+ self.class_to_idx = {cls: idx for idx, cls in enumerate(self.classes)}
15
+ self.file_list = self.create_file_list()
16
+
17
+ def create_file_list(self):
18
+ file_list = []
19
+ for cls in self.classes:
20
+ class_path = os.path.join(self.root_dir, cls)
21
+ for file_name in os.listdir(class_path):
22
+ file_path = os.path.join(class_path, file_name)
23
+ file_list.append((file_path, self.class_to_idx[cls]))
24
+ return file_list
25
+
26
+ def __len__(self):
27
+ return len(self.file_list)
28
+
29
+ def __getitem__(self, idx):
30
+ img_path, label = self.file_list[idx]
31
+ image = np.array(Image.open(img_path).convert('L'))
32
+ target = [0]*7
33
+ target[label] = 1
34
+ target = torch.FloatTensor(target)
35
+
36
+ if self.transform:
37
+ image = config.transform(image=image)["image"]
38
+
39
+ return image, target
model.py ADDED
@@ -0,0 +1,151 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # from torch import nn as nn
2
+ #
3
+ #
4
+ # class EmotionModel(nn.Module):
5
+ # def __init__(self, in_channels=1, num_classes=7):
6
+ # super(EmotionModel, self).__init__()
7
+ # self.conv1 = nn.Conv2d(
8
+ # in_channels=in_channels, out_channels=256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1)
9
+ # )
10
+ # self.relu1 = nn.ReLU()
11
+ # self.pool1 = nn.MaxPool2d(kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))
12
+ # self.drop1 = nn.Dropout2d(0.4)
13
+ #
14
+ # self.conv2 = nn.Conv2d(in_channels=256, out_channels=512, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))
15
+ # self.relu2 = nn.ReLU()
16
+ # self.pool2 = nn.MaxPool2d(kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))
17
+ # self.drop2 = nn.Dropout2d(0.4)
18
+ #
19
+ # self.conv3 = nn.Conv2d(in_channels=512, out_channels=512, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))
20
+ # self.relu3 = nn.ReLU()
21
+ # self.pool3 = nn.MaxPool2d(kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))
22
+ # self.drop3 = nn.Dropout2d(0.4)
23
+ #
24
+ # self.conv4 = nn.Conv2d(
25
+ # in_channels=512, out_channels=512 * 4 * 4, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1)
26
+ # )
27
+ # self.relu4 = nn.ReLU()
28
+ # self.pool4 = nn.MaxPool2d(kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))
29
+ # self.drop4 = nn.Dropout2d(0.4)
30
+ #
31
+ # self.fc1 = nn.Linear(in_features=512 * 4 * 4, out_features=512)
32
+ # self.relu5 = nn.ReLU()
33
+ # self.drop5 = nn.Dropout(0.3)
34
+ # self.fc2 = nn.Linear(in_features=512, out_features=256)
35
+ # self.relu6 = nn.ReLU()
36
+ # self.drop6 = nn.Dropout(0.3)
37
+ # self.fc3 = nn.Linear(in_features=256, out_features=num_classes)
38
+ # self.softmax = nn.Softmax(dim=1)
39
+ #
40
+ # def forward(self, x):
41
+ # x = self.conv1(x)
42
+ # x = self.relu1(x)
43
+ # x = self.pool1(x)
44
+ # x = self.drop1(x)
45
+ # x = self.conv2(x)
46
+ # x = self.relu2(x)
47
+ # x = self.pool2(x)
48
+ # x = self.drop2(x)
49
+ # x = self.conv3(x)
50
+ # x = self.relu3(x)
51
+ # x = self.pool3(x)
52
+ # x = self.drop3(x)
53
+ # x = self.conv4(x)
54
+ # x = self.relu4(x)
55
+ # x = self.pool4(x)
56
+ # x = self.drop4(x)
57
+ # x = x.view(-1, 512 * 4 * 4)
58
+ # x = self.fc1(x)
59
+ # x = self.relu5(x)
60
+ # x = self.drop5(x)
61
+ # x = self.fc2(x)
62
+ # x = self.relu6(x)
63
+ # x = self.drop6(x)
64
+ # x = self.fc3(x)
65
+ # x = self.softmax(x)
66
+ # return x
67
+
68
+ import torch.nn as nn
69
+
70
+
71
+ class EmotionModel(nn.Module):
72
+ def __init__(self, in_channels=1, num_classes=7):
73
+ super(EmotionModel, self).__init__()
74
+ self.conv1 = nn.Conv2d(in_channels, 256, kernel_size=3, stride=2, padding=1)
75
+ self.bn1 = nn.BatchNorm2d(256)
76
+ self.relu1 = nn.ReLU()
77
+ self.pool1 = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
78
+ self.drop1 = nn.Dropout2d(0.4)
79
+
80
+ self.conv2 = nn.Conv2d(256, 512, kernel_size=3, stride=2, padding=1)
81
+ self.bn2 = nn.BatchNorm2d(512)
82
+ self.relu2 = nn.ReLU()
83
+ self.pool2 = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
84
+ self.drop2 = nn.Dropout2d(0.4)
85
+
86
+ self.conv3 = nn.Conv2d(512, 512, kernel_size=3, stride=2, padding=1)
87
+ self.bn3 = nn.BatchNorm2d(512)
88
+ self.relu3 = nn.ReLU()
89
+ self.pool3 = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
90
+ self.drop3 = nn.Dropout2d(0.4)
91
+
92
+ self.conv4 = nn.Conv2d(512, 512 * 4 * 4, kernel_size=3, stride=2, padding=1)
93
+ self.bn4 = nn.BatchNorm2d(512 * 4 * 4)
94
+ self.relu4 = nn.ReLU()
95
+ self.pool4 = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
96
+ self.drop4 = nn.Dropout2d(0.4)
97
+
98
+ self.fc1 = nn.Linear(512 * 4 * 4, 512)
99
+ self.bn_fc1 = nn.BatchNorm1d(512)
100
+ self.relu5 = nn.ReLU()
101
+ self.drop5 = nn.Dropout(0.3)
102
+
103
+ self.fc2 = nn.Linear(512, 256)
104
+ self.bn_fc2 = nn.BatchNorm1d(256)
105
+ self.relu6 = nn.ReLU()
106
+ self.drop6 = nn.Dropout(0.3)
107
+
108
+ self.fc3 = nn.Linear(256, num_classes)
109
+ self.softmax = nn.Softmax(dim=1)
110
+
111
+ def forward(self, x):
112
+ x = self.conv1(x)
113
+ x = self.bn1(x)
114
+ x = self.relu1(x)
115
+ x = self.pool1(x)
116
+ x = self.drop1(x)
117
+
118
+ x = self.conv2(x)
119
+ x = self.bn2(x)
120
+ x = self.relu2(x)
121
+ x = self.pool2(x)
122
+ x = self.drop2(x)
123
+
124
+ x = self.conv3(x)
125
+ x = self.bn3(x)
126
+ x = self.relu3(x)
127
+ x = self.pool3(x)
128
+ x = self.drop3(x)
129
+
130
+ x = self.conv4(x)
131
+ x = self.bn4(x)
132
+ x = self.relu4(x)
133
+ x = self.pool4(x)
134
+ x = self.drop4(x)
135
+
136
+ x = x.view(-1, 512 * 4 * 4)
137
+
138
+ x = self.fc1(x)
139
+ x = self.bn_fc1(x)
140
+ x = self.relu5(x)
141
+ x = self.drop5(x)
142
+
143
+ x = self.fc2(x)
144
+ x = self.bn_fc2(x)
145
+ x = self.relu6(x)
146
+ x = self.drop6(x)
147
+
148
+ x = self.fc3(x)
149
+ x = self.softmax(x)
150
+
151
+ return x
requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ torch
2
+ streamlit
3
+ tqdm
4
+ albumentations
5
+ numpy
6
+ Pillow
7
+ matplotlib
train.py ADDED
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import time
2
+ import numpy as np
3
+ import torch
4
+ from PIL import Image
5
+ from matplotlib import pyplot as plt
6
+ from torch import nn as nn, optim
7
+ from torch.utils.data import DataLoader
8
+ from tqdm import tqdm
9
+ import config
10
+ from dataset import EmotionDataset
11
+ from model import EmotionModel
12
+ from utils import load_checkpoint, save_checkpoint
13
+
14
+
15
+ def train_fn(model, loader, opt, criterion, epoch):
16
+ loop = tqdm(loader, leave=True)
17
+ model.train()
18
+ epoch_loss = 0.0
19
+
20
+ for idx, (image, label) in enumerate(loop):
21
+ total_acc, total_count = 0, 0
22
+ image = image.to(config.DEVICE)
23
+ label = label.to(config.DEVICE)
24
+ opt.zero_grad()
25
+ predicted_label = model(image)
26
+ loss = criterion(predicted_label, label)
27
+ epoch_loss += loss.item()
28
+ loss.backward()
29
+ torch.nn.utils.clip_grad_norm_(model.parameters(), 0.1)
30
+ opt.step()
31
+ total_acc += (predicted_label.argmax(1) == label.argmax(1)).sum().item()
32
+ total_count += label.size(0)
33
+ loop.set_postfix({"epoch": epoch, "loss": epoch_loss / len(loader), "accuracy": total_acc / total_count})
34
+
35
+
36
+ def main():
37
+ model = EmotionModel().to(config.DEVICE)
38
+ opt = optim.Adam(model.parameters(), lr=config.LEARNING_RATE, betas=(0.5, 0.999), )
39
+ criterion = nn.CrossEntropyLoss()
40
+
41
+ # if config.LOAD_MODEL:
42
+ # load_checkpoint(
43
+ # config.CHECKPOINT, model, opt, config.LEARNING_RATE,
44
+ # )
45
+
46
+ train_dataset = EmotionDataset(root_dir=config.TRAIN_DIR)
47
+ train_loader = DataLoader(
48
+ train_dataset,
49
+ batch_size=config.BATCH_SIZE,
50
+ shuffle=True,
51
+ num_workers=config.NUM_WORKERS,
52
+ )
53
+ val_dataset = EmotionDataset(root_dir=config.VAL_DIR)
54
+ val_loader = DataLoader(
55
+ val_dataset,
56
+ batch_size=config.BATCH_SIZE,
57
+ shuffle=True,
58
+ num_workers=config.NUM_WORKERS,
59
+ )
60
+
61
+ total_accu = None
62
+ # scheduler = torch.optim.lr_scheduler.StepLR(opt, 1, gamma=0.5)
63
+ scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(opt, patience=2, verbose=True)
64
+ for epoch in range(config.NUM_EPOCHS):
65
+ epoch_start_time = time.time()
66
+ train_fn(
67
+ model, train_loader, opt, criterion, epoch
68
+ )
69
+ accu_val, loss_val = evaluate(model, criterion, val_loader)
70
+ # if total_accu is not None and total_accu > accu_val:
71
+ # scheduler.step()
72
+ # else:
73
+ # total_accu = accu_val
74
+ scheduler.step(loss_val)
75
+ print("+" + "-" * 19 + "+" + "-" * 15 + "+" + "-" * 20 + "+" + "-" * 24 + "+")
76
+ print(
77
+ "| end of epoch: {:3d} | time: {:6.2f}s | val_loss: {:8.3f} | "
78
+ "val_accuracy: {:8.3f} |".format(
79
+ epoch, time.time() - epoch_start_time, loss_val, accu_val
80
+ )
81
+ )
82
+ print("+" + "-" * 19 + "+" + "-" * 15 + "+" + "-" * 20 + "+" + "-" * 24 + "+")
83
+
84
+ if config.SAVE_MODEL:
85
+ save_checkpoint(model, opt, filename=config.CHECKPOINT)
86
+
87
+
88
+ def test():
89
+ model = EmotionModel().to(config.DEVICE)
90
+ opt = optim.Adam(model.parameters(), lr=config.LEARNING_RATE, betas=(0.5, 0.999), )
91
+ criterion = nn.CrossEntropyLoss()
92
+ if config.LOAD_MODEL:
93
+ load_checkpoint(
94
+ config.CHECKPOINT, model, opt, config.LEARNING_RATE,
95
+ )
96
+
97
+ val_dataset = EmotionDataset(root_dir=config.VAL_DIR)
98
+ val_loader = DataLoader(
99
+ val_dataset,
100
+ batch_size=config.BATCH_SIZE,
101
+ shuffle=True,
102
+ num_workers=config.NUM_WORKERS,
103
+ )
104
+ # print(evaluate(model, criterion, val_loader))
105
+ model.eval()
106
+ print(val_dataset.class_to_idx)
107
+ image = np.array(Image.open("images/validation/angry/245.jpg").convert('L'))
108
+ plt.imshow(image)
109
+ image = config.transform(image=image)["image"]
110
+ image = image.to(config.DEVICE)
111
+ image = torch.unsqueeze(image, dim=0)
112
+ score = model(image)
113
+ print(torch.argmax(score))
114
+ plt.show()
115
+
116
+
117
+ def evaluate(model, criterion, dataloader):
118
+ model.eval()
119
+ total_correct = 0
120
+ total_samples = 0
121
+ total_loss = 0.0
122
+
123
+ with torch.no_grad():
124
+ for inputs, labels in dataloader:
125
+ inputs, labels = inputs.to(config.DEVICE), labels.to(config.DEVICE)
126
+
127
+ outputs = model(inputs)
128
+ loss = criterion(outputs, labels)
129
+
130
+ total_loss += loss.item()
131
+
132
+ _, predicted = torch.max(outputs, 1)
133
+
134
+ total_correct += (predicted == labels.argmax(1)).sum().item()
135
+ total_samples += labels.size(0)
136
+
137
+ accuracy = total_correct / total_samples
138
+ average_loss = total_loss / len(dataloader)
139
+
140
+ return accuracy, average_loss
141
+
142
+
143
+ if __name__ == "__main__":
144
+ test()
uploads/31572.jpg ADDED
utils.py ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import config
3
+
4
+
5
+ def save_checkpoint(model, optimizer, filename="my_checkpoint.pth.tar"):
6
+ print("=> Saving checkpoint")
7
+ checkpoint = {
8
+ "state_dict": model.state_dict(),
9
+ "optimizer": optimizer.state_dict(),
10
+ }
11
+ torch.save(checkpoint, filename)
12
+
13
+
14
+ def load_checkpoint(checkpoint_file, model, optimizer, lr):
15
+ print("=> Loading checkpoint")
16
+ checkpoint = torch.load(checkpoint_file, map_location=config.DEVICE)
17
+ model.load_state_dict(checkpoint["state_dict"])
18
+ optimizer.load_state_dict(checkpoint["optimizer"])
19
+
20
+ for param_group in optimizer.param_groups:
21
+ param_group["lr"] = lr