alexnet进行花朵分类

1 对花数据集进行分类

原址:https://gitlab.diantouedu.cn/QY/test1/tree/master。

本文代码:https://github.com/Guoxn1/ai。

数据集需要自行从原址处下载。

image-20231129092517757

大致如下,一共分为训练集和测试集,一共五种花。本文使用自构建的alexnet和pretrained的alexnet进行训练,对比效果。

2 自构建alexnet

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
from tqdm import tqdm
import torch
import torchvision
from torch import nn
from torchvision import transforms,datasets
import torchvision.transforms as trans
import os
import sys
import matplotlib.pyplot as plt




def get_net(num_classes1):

class Alexnet(nn.Module):
def __init__(self,num_classes):
super(Alexnet,self).__init__()
self.features = nn.Sequential(
nn.Conv2d(3, 96, kernel_size=11, stride=4, padding=2), # input[3, 224, 224] output[96, 55, 55]
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3, stride=2), # output[96, 27, 27]

nn.Conv2d(96, 256, kernel_size=5, padding=2), # output[256, 27, 27]
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3, stride=2), # output[256, 13, 13]

nn.Conv2d(256, 384, kernel_size=3, padding=1), # output[384, 13, 13]
nn.ReLU(inplace=True),

nn.Conv2d(384, 384, kernel_size=3, padding=1), # output[384, 13, 13]
nn.ReLU(inplace=True),

nn.Conv2d(384, 256, kernel_size=3, padding=1), # output[256, 13, 13]
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3, stride=2), # output[256, 6, 6]

)
self.classifier = nn.Sequential(
nn.Dropout(p=0.5),
nn.Linear(256 * 6 * 6, 4096),
nn.ReLU(inplace=True),

nn.Dropout(p=0.5),
nn.Linear(4096, 4096),
nn.ReLU(inplace=True),

nn.Linear(4096, num_classes),
)

def forward(self,x):
x = self.features(x)
x = torch.flatten(x,start_dim=1)
x = self.classifier(x)
return x

net = Alexnet(num_classes1)
return net

def data_loader(data_path,batch_size):
transforms1 = {
"train":transforms.Compose([
transforms.Resize(224),
transforms.CenterCrop(224),
transforms.RandomHorizontalFlip(224),
transforms.ToTensor(),
transforms.Normalize((0.5,0.5,0.5),(0.5,0.5,0.5))
]),
"test":transforms.Compose([
transforms.Resize((224,224)),
transforms.ToTensor(),
transforms.Normalize((0.5,0.5,0.5),(0.5,0.5,0.5)),

])
}
train_dataset = datasets.ImageFolder(root=os.path.join(data_path,"train"),transform=transforms1["train"])
test_dataset = datasets.ImageFolder(root=os.path.join(data_path,"val"),transform=transforms1["test"])

train_loader = torch.utils.data.DataLoader(train_dataset,batch_size,shuffle=True)
test_loader = torch.utils.data.DataLoader(test_dataset,batch_size,shuffle=False)
return train_loader,test_loader

def plot_acc(epochs,train_acc_li,test_acc_li):
plt.plot(range(1,epochs+1), train_acc_li, label="train_acc",color="red")
plt.plot(range(1,epochs+1), test_acc_li, label="test_acc",color="blue")
plt.xlabel("epochs")
plt.ylabel("acc")
plt.legend()

plt.title("epoch-acc")
plt.show()


def test(net,test_loader,device):
net.eval()
acc_num = torch.zeros(1).to(device)
sample_num = 0
test_bar = tqdm(test_loader,file=sys.stdout,ncols=100)
with torch.no_grad():
for data in test_bar:
images,label = data
sample_num += images.shape[0]
images = images.to(device)
label = label.to(device)
output = net(images)
pred_class = torch.max(output,dim=1)[1]
acc_num += torch.eq(pred_class,label).sum()
test_acc = acc_num.item()/sample_num
return test_acc

def train(net,train_loader,loss_func,optimzer,lr,device):
net.train()
acc_num = torch.zeros(1).to(device)
sample_num = 0
train_bar = tqdm(train_loader,file=sys.stdout,ncols=100)
for data in train_bar:
images,label = data
sample_num += images.shape[0]
images = images.to(device)
label = label.to(device)
optimzer.zero_grad()
output = net(images)
pred_class = torch.max(output,dim=1)[1]
acc_num += torch.eq(pred_class,label).sum()
loss = loss_func(output,label)
loss.backward()
optimzer.step()
train_acc = acc_num.item()/sample_num
return train_acc

def main():
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
data_path = "./data"
batch_size = 64
train_loader,test_loader = data_loader(data_path,64)
num_classes = 5
net = get_net(num_classes)
net.to(device)
lr = 0.001
epochs = 50
loss_func = nn.CrossEntropyLoss()
optimzer = torch.optim.Adam(net.parameters(),lr=lr)
print(f"using {device}---")

save_path = os.path.abspath(os.path.join(os.getcwd(),"result/alexnet"))
if not os.path.exists(save_path):
os.makedirs(save_path)
train_acc_li,test_acc_li = [],[]
for epoch in range(epochs):
train_acc_li.append(train(net,train_loader,loss_func,optimzer,lr,device))
test_acc_li.append(test(net,test_loader,device))

plot_acc(epochs,train_acc_li,test_acc_li)
torch.save(net.state_dict(), os.path.join(save_path, "AlexNet.pth") )
print(train_acc_li[-1],test_acc_li[-1])
print("train is finished---")



main()

结果如下:

image-20231129092655208

adam优化器,lr=0.001,epoch是50轮。

训练精度在98,测试精度在70,应该是过拟合了,后期可以考虑加一些正则项,比如droup层和权重衰退。

3 使用预训练的模型

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
from tqdm import tqdm
import torch
import torchvision
from torch import nn
from torchvision import transforms,datasets
import torchvision.transforms as trans
import os
import sys
import matplotlib.pyplot as plt


def data_loader(data_path,batch_size):
transforms1 = {
"train":transforms.Compose([
transforms.Resize(224),
transforms.CenterCrop(224),
transforms.RandomHorizontalFlip(224),
transforms.ToTensor(),
transforms.Normalize((0.5,0.5,0.5),(0.5,0.5,0.5))
]),
"test":transforms.Compose([
transforms.Resize((224,224)),
transforms.ToTensor(),
transforms.Normalize((0.5,0.5,0.5),(0.5,0.5,0.5)),

])
}
train_dataset = datasets.ImageFolder(root=os.path.join(data_path,"train"),transform=transforms1["train"])
test_dataset = datasets.ImageFolder(root=os.path.join(data_path,"val"),transform=transforms1["test"])

train_loader = torch.utils.data.DataLoader(train_dataset,batch_size,shuffle=True)
test_loader = torch.utils.data.DataLoader(test_dataset,batch_size,shuffle=False)
return train_loader,test_loader

def get_net(num_classes):
model = torchvision.models.alexnet(pretrained=True)
model_fc = model.classifier[6].in_features
model.classifier[6] = torch.nn.Linear(in_features=model_fc,out_features=num_classes)
return model


def test(net,test_loader,device):
net.eval()
acc_num = torch.zeros(1).to(device)
sample_num = 0
test_bar = tqdm(test_loader,file=sys.stdout,ncols=100)
with torch.no_grad():
for data in test_bar:
images,label = data
sample_num += images.shape[0]
images = images.to(device)
label = label.to(device)
output = net(images)
pred_class = torch.max(output,dim=1)[1]
acc_num += torch.eq(pred_class,label).sum()
test_acc = acc_num.item()/sample_num
return test_acc

def train(net,train_loader,loss_func,optimzer,lr,device):
net.train()
acc_num = torch.zeros(1).to(device)
sample_num = 0
train_bar = tqdm(train_loader,file=sys.stdout,ncols=100)
for data in train_bar:
images,label = data
sample_num += images.shape[0]
images = images.to(device)
label = label.to(device)
optimzer.zero_grad()
output = net(images)
pred_class = torch.max(output,dim=1)[1]
acc_num += torch.eq(pred_class,label).sum()
loss = loss_func(output,label)
loss.backward()
optimzer.step()
train_acc = acc_num.item()/sample_num
return train_acc

def plot_acc(epochs,train_acc_li,test_acc_li):
plt.plot(range(1,epochs+1), train_acc_li, label="train_acc",color="red")
plt.plot(range(1,epochs+1), test_acc_li, label="test_acc",color="blue")
plt.xlabel("epochs")
plt.ylabel("acc")
plt.legend()

plt.title("epoch-acc")
plt.show()

def main():
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
data_path = "./data"
batch_size = 64
train_loader,test_loader = data_loader(data_path,64)
num_classes = 5
net = get_net(num_classes)
net.to(device)
lr = 0.0001
epochs = 20
loss_func = nn.CrossEntropyLoss()
optimzer = torch.optim.Adam(net.parameters(),lr=lr)
save_path = os.path.abspath(os.path.join(os.getcwd(),"result/alexnet"))
if not os.path.exists(save_path):
os.makedirs(save_path)
print(f"using {device}---")

train_acc_li,test_acc_li = [],[]
for epoch in range(epochs):
train_acc_li.append(train(net,train_loader,loss_func,optimzer,lr,device))
test_acc_li.append(test(net,test_loader,device))

torch.save(net.state_dict(), os.path.join(save_path, "pre_AlexNet.pth") )
print(train_acc_li[-1],test_acc_li[-1])
plot_acc(epochs,train_acc_li,test_acc_li)
print("train is finished---")

main()

结果如下:

image-20231129092852618

优化器adam,lr=0.0001,epoch为20.

训练精度达到100,测试精度是88,产生了一定的过拟合,不过精度上还可以,比自构建的alexnet好一点。并且,由于是预训练之后的,我们将学习率降低了10倍,训练次数降低了2.5倍,不过效果依然比自己训练的好。

原因就是自己的训练集小,不如在预训练的模型上进行微调。


alexnet进行花朵分类
http://example.com/2023/11/29/alexnet进行花朵分类/
作者
Guoxin
发布于
2023年11月29日
许可协议