基于神经网络的鸾尾花分类

1 简介

神经网络,看起来像各种各样堆叠在一起的函数,然后根据损失函数运用梯度下降算法和链式法则,对参数进行更新,使得神经网络能尽可能的拟合我们给出的数据。

为了防止欠拟合,可以添加尽可能多的函数的数量和种类;为了防止过拟合,则尽可能减少函数的数量和种类。

为了使神经网络拟合各种各样的情况(主要是非线性情况),加入了各式各样的激活函数。

还提出正则化,标准化等方法。

这次处理一个鸾尾花数据集,这个数据集如果提前了解的话,可以知道这个数据集就是线性就可以比较好的拟合。

并且在这次实验中,竟然。。达到了测试集100%的正确率。

原出处,https://gitlab.diantouedu.cn/QY/test1/tree/master/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD%E7%B3%BB%E7%BB%9F%E5%AE%9E%E6%88%98%E7%AC%AC%E4%B8%89%E6%9C%9F/%E5%AE%9E%E6%88%98%E4%BB%A3%E7%A0%81/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C%E5%AE%9E%E7%8E%B0%E9%B8%A2%E5%B0%BE%E8%8A%B1%E5%88%86%E7%B1%BB。

和源代码略有不同,增加了“根据验证集调整超参数学习率”的操作,并且函数化了一些操作。

所有代码,在我的仓库中,https://github.com/Guoxn1/ai。

2 数据集

直接在一个文件中,前四列使鸾尾花的特征,后一列是鸾尾花的标签。

image-20231031175534283

3 项目结构

image-20231031175619287

可以不看yihuo.py,和项目无关。

__pycache__是字节码,不用管。

result下面有个weight文件夹,用来保存我们生成的神经网络。

load_data.py是加载数据的,包括标准化,设置数据的类型等。

main.py是构建神经网络来进行训练的。主要就是这俩。

load_data.py

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
from torch.utils.data import Dataset
import os
import pandas as pd
import numpy as np
import torch
from sklearn.preprocessing import StandardScaler

class iris_load(Dataset):
def __init__(self,datapath:str,transform=None):
self.datapath = datapath
self.transform = transform
print(datapath)
#assert os.path.exists(datapath),"dataset doesnt exist"

df = pd.read_csv(self.datapath,names=[0,1,2,3,4])
# 把标签转换为数字
d = {'Iris-setosa':0, 'Iris-versicolor':1, 'Iris-virginica':2}
df[4] = df[4].map(d)

data = df.iloc[:,0:4]
label = df.iloc[:,4]

data = np.array(data)
scaler = StandardScaler()
data = scaler.fit_transform(data)
label = np.array(label)

self.data = torch.from_numpy((np.array(data,dtype='float32')))
self.label= torch.from_numpy(np.array(label,dtype='int64') )
self.data_num = len(label)

def __len__(self):
return self.data_num

def __getitem__(self, idx):
self.data = list(self.data)
self.label = list(self.label)
return self.data[idx], self.label[idx]

# data = iris_load("深度学习基础\神经网络\基于神经网络的鸾尾花分类\Iris_data.txt")
# print(data)

main.py

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
import os
import argparse
import sys
from torch.utils.data import DataLoader
from tqdm import tqdm
import torch
import torch.optim as optim
import torch.nn as nn
from load_data import iris_load

parse = argparse.ArgumentParser()
parse.add_argument("--num_classes",type=int,default=100,help="the number of classes")
parse.add_argument("--epochs",type=int,default=20,help="the number of training epoch")
parse.add_argument("--batch_size",type=int,default=16,help="batch size of training")
parse.add_argument("--lr",type=float,default=0.005,help="star learning rate")
parse.add_argument("--data_path",type=str,default="深度学习基础\神经网络\基于神经网络的鸾尾花分类\Iris_data.txt")
parse.add_argument("--device",default="cuda",help="device id(cpu)")
opt = parse.parse_args()

class Iris_network(nn.Module):
def __init__(self,in_dim,out_dim):
super(Iris_network,self).__init__()
self.layer1 = nn.Linear(in_dim,10)
self.layer2 = nn.Linear(10,6)
self.layer3 = nn.Linear(6,3)

def forward(self,x):
x = self.layer1(x)
x = self.layer2(x)
x = self.layer3(x)
return x



def test(model,data):
model.eval()
acc_num = 0.0

with torch.no_grad():
for data1 in data:
datas,label = data1
output = model(datas.to(device))

predict = torch.max(output,dim=1)[1]
acc_num += torch.eq(predict,label.to(device)).sum().item()
accuratcy = acc_num/len(data)
return accuratcy

def train(train_loader,validate_loader):
best_val_accuracy = 0.0
patience = 3
no_improvement_epochs = 0
lr_decay_factor = 0.98
model = Iris_network(4,3).to(device)
loss_function = nn.CrossEntropyLoss()
pg = [p for p in model.parameters() if p.requires_grad]
optimizer = optim.Adam(pg,lr=opt.lr)

save_path = "result/weights"
if os.path.exists(save_path) is False:
os.makedirs(save_path)

for epoch in range(opt.epochs):
model.train()

train_bar = tqdm(train_loader, file=sys.stdout, ncols=100)

for data in train_bar:
datas,label = data
label = label.squeeze(-1)
#data.shape[0] 表示当前小批量数据中的样本数量。
optimizer.zero_grad()
outputs = model(datas.to(device))
loss = loss_function(outputs,label.to(device))
loss.backward()
optimizer.step()

val_accurate = test( model, validate_loader)
print('[epoch %d] val_accuracy: %.3f' % (epoch + 1, val_accurate))
# 在这里,可以根据验证集返回的正确率调整超参数,比如学习率

if val_accurate > best_val_accuracy:
torch.save(model.state_dict(), os.path.join(save_path, "NN.pth") )
best_val_accuracy = val_accurate
else:
no_improvement_epochs += 1
# 如果连续多个轮次没有改善,则降低学习率
if no_improvement_epochs >= patience:
# 使用学习率衰减策略,如将学习率乘以一个衰减因子
new_learning_rate = opt.lr * lr_decay_factor
# 更新优化器中的学习率
for param_group in optimizer.param_groups:
param_group['lr'] = new_learning_rate
# 打印学习率调整信息
print('Learning rate adjusted to %.6f' % new_learning_rate)
# 重置没有改善的轮次计数器
no_improvement_epochs = 0

return model

def get_loader(datapath):
data = iris_load("Iris_data.txt")
train_size = int(len(data)*0.7)
validate_size = int(len(data)*0.2)
test_size = int(len(data)*0.1)

train,validate,test = torch.utils.data.random_split(data,[train_size,validate_size,test_size])

train_loader = DataLoader(train,batch_size=opt.batch_size,shuffle=False)
validate_loader = DataLoader(validate,batch_size=1,shuffle=False)
test_loader = DataLoader(test,batch_size=1,shuffle=False)
print("Training set data size:", len(train_loader)*opt.batch_size, ",Validating set data size:", len(validate_loader), ",Testing set data size:", len(test_loader))

return train_loader,validate_loader,test_loader

def main(args):

train_loader,validate_loader,test_loader = get_loader("深度学习基础\神经网络\基于神经网络的鸾尾花分类\Iris_data.txt")

model = train(train_loader,validate_loader)

test_accurancy = test(model,test_loader)
print(' test_accuracy: %.3f' % ( test_accurancy))




if __name__ == '__main__':
device = torch.device(opt.device if torch.cuda.is_available() else "cpu")
main(opt)





image-20231031180309943

正确率居然达到了1.。。。


基于神经网络的鸾尾花分类
http://example.com/2023/10/29/基于神经网络的鸾尾花分类/
作者
Guoxin
发布于
2023年10月29日
许可协议