-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathLeNet.py
178 lines (155 loc) · 5.72 KB
/
LeNet.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
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
177
178
# LEnet 网络
################################
# 输入 1*28*28
# conv2 6*28*28
# maxpool 6*14*14
# conv2 16*10*10
# maxpool 16*5*5
# linear 120
# linear 84
# linear 10
###################################
import torch
import torchvision as tv
import torchvision.transforms as transforms
import torch.nn as nn
import torch.optim as optim
import argparse
import platform
import copy
# 定义网络结构
class LeNet(nn.Module):
def __init__(self):
super(LeNet, self).__init__()
self.conv1 = nn.Sequential( #input_size=(1*28*28)
nn.Conv2d(1, 6, 5, 1, 2), #padding=2保证输入输出尺寸相同
nn.ReLU(), #input_size=(6*28*28)
nn.MaxPool2d(kernel_size=2, stride=2),#output_size=(6*14*14)
)
self.conv2 = nn.Sequential(
nn.Conv2d(6, 16, 5),
nn.ReLU(), #input_size=(16*10*10)
nn.MaxPool2d(2, 2) #output_size=(16*5*5)
)
self.fc1 = nn.Sequential(
nn.Linear(16 * 5 * 5, 120),
nn.ReLU()
)
self.fc2 = nn.Sequential(
nn.Linear(120, 84),
nn.ReLU()
)
self.fc3 = nn.Linear(84, 10)
# 定义前向传播过程,输入为x
def forward(self, x):
x = self.conv1(x)
x = self.conv2(x)
# nn.Linear()的输入输出都是维度为一的值,所以要把多维度的tensor展平成一维
x = x.view(x.size()[0], -1)
x = self.fc1(x)
x = self.fc2(x)
x = self.fc3(x)
return x
# 训练
if __name__ == "__main__":
# 定义是否使用GPU
# device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
device = torch.device("cpu")
# 使得我们能够手动输入命令行参数,就是让风格变得和Linux命令行差不多
parser = argparse.ArgumentParser()
parser.add_argument('--outf', default='./testmodel/', help='folder to output images and model checkpoints') # 模型保存路径
parser.add_argument('--net', default='./testmodel/net.pth', help="path to netG (to continue training)") # 模型加载路径
opt = parser.parse_args()
# 超参数设置
EPOCH = 15 # 遍历数据集次数
BATCH_SIZE = 64 # 批处理尺寸(batch_size)
LR = 0.001 # 学习率
# 定义数据预处理方式
transform = transforms.ToTensor()
# 判断系统平台
def is_windowssystem():
return 'Windows' in platform.system()
def is_linuxsystem():
return 'Linux' in platform.system()
if is_windowssystem():
MNIST_data = "./dataset" # windows
if is_linuxsystem():
MNIST_data = "/home/yjdu/federatedlearning_DP_torch/dataset" # linux
# 定义训练数据集
trainset = tv.datasets.MNIST(
root=MNIST_data,
train=True,
download=False,
transform=transform)
# 定义训练批处理数据
trainloader = torch.utils.data.DataLoader(
trainset,
batch_size=BATCH_SIZE,
shuffle=True,
)
# 定义测试数据集
testset = tv.datasets.MNIST(
root=MNIST_data,
train=False,
download=False,
transform=transform)
# 定义测试批处理数据
testloader = torch.utils.data.DataLoader(
testset,
batch_size=BATCH_SIZE,
shuffle=False,
)
# 定义损失函数loss function 和优化方式(采用SGD)
net = LeNet().to(device)
criterion = nn.CrossEntropyLoss() # 交叉熵损失函数,通常用于多分类问题上
optimizer = optim.SGD(net.parameters(), lr=LR, momentum=0.9)
for epoch in range(EPOCH):
sum_loss = 0.0
# 数据读取
for i, data in enumerate(trainloader):
inputs, labels = data
inputs, labels = inputs.to(device), labels.to(device)
# 梯度清零
optimizer.zero_grad()
# forward + backward
outputs = net(inputs)
loss = criterion(outputs, labels)
loss.backward()
# # 保存梯度
# client_dict = dict()
# params_modules = list(net.named_parameters())
# for params_module in params_modules:
# (name, params) = params_module
# params_grad = copy.deepcopy(params.grad)
# client_dict[name] = params_grad
#
# # 梯度清零
# optimizer.zero_grad()
#
# # 加载梯度
# params_modules = list(net.named_parameters())
# for params_module in params_modules:
# (name, params) = params_module
# params.grad = client_dict[name] # 用字典中存储的子模型的梯度覆盖server中的参数梯度
optimizer.step()
# 每训练100个batch打印一次平均loss
sum_loss += loss.item()
if i % 100 == 99:
print('[%d, %d] loss: %.03f'
% (epoch + 1, i + 1, sum_loss / 100))
sum_loss = 0.0
# 每跑完一次epoch测试一下准确率
with torch.no_grad():
correct = 0
total = 0
for data in testloader:
images, labels = data
images, labels = images.to(device), labels.to(device)
outputs = net(images)
# 取得分最高的那个类
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum()
print('第%d个epoch的识别准确率为:%d%%' % (epoch + 1, (100 * correct / total)))
torch.save(net.state_dict(), '%s/net_%03d.pth' % (opt.outf, epoch + 1))
print('successfully save the model to %s/net_%03d.pth' % (opt.outf, epoch + 1))