resnext和SEresnet代码详解(⼀⾏⼀⾏代码详解)resnext是由resnet50演变⽽来,于resnet50的区别就是在卷积块和激活函数之间其增加了bn板块,是为了对数据进⾏归⼀化处理,还有就是增加了分组,在论⽂中是将resnet⾥的图像channel分成了32组再加上bn板块即构成了resnext,⽽SEresnet实在resnext的基础上演变⽽来的,其是在resnext上在每个block⾥⾯增加了对原图像进⾏加权操作,主要通过全局平均池化、全连接线性层、ReLU操作、全连接线性层以及Sigmoid函数求得各个通道的权重值,再通过Scale(乘积)操作完成加权。在实例中,⽤卷积层代替全连接层,试图减少图⽚的语义损失。具体参见这个博主的博客,讲的是⾮常的详细!
下⾯分别附上resnext的代码还有resnet的代码,可以直接运⾏!!
下⾯是resnext的代码:
1resnext的代码
2
3import torch
4from torch import nn
5
6import torch
as nn
8
9class Block(nn.Module):
10 def __init__(lf,in_channels, out_channels, stride=1, is_shortcut=Fal):
11 super(Block,lf).__init__()
12 # 继承block的⽗类进⾏初始化。⽽且是⽤⽗类的初始化⽅法来初始化继承的属性
13 lf.relu = nn.ReLU(inplace=True)
14 # inplace-选择是否进⾏覆盖运算,即是否将得到的值计算得到的值覆盖之前的值
15 lf.is_shortcut = is_shortcut
16 lf.conv1 = nn.Sequential(
17 # Sequential⼀个有序的容器,神经⽹络模块将按照在传⼊构造器的顺序依次被添加到计算图中执⾏,
18 nn.Conv2d(in_channels, out_channels // 2, kernel_size=1,stride=stride,bias=Fal),
19 nn.BatchNorm2d(out_channels // 2),
20 # 添加BatchNorm2d进⾏数据的归⼀化处理,这使得数据在进⾏Relu之前不会因为数据过⼤⽽导致⽹络性能的不稳定
21 nn.ReLU()
22 )
23 lf.conv2 = nn.Sequential(
24 nn.Conv2d(out_channels // 2, out_channels // 2, kernel_size=3, stride=1, padding=1, groups=32,
25 bias=Fal),
26 nn.BatchNorm2d(out_channels // 2),
27 nn.ReLU()home working
28 )
29 lf.conv3 = nn.Sequential(
30 nn.Conv2d(out_channels // 2, out_channels, kernel_size=1,stride=1,bias=Fal),
31 nn.BatchNorm2d(out_channels),
32 )
33 if is_shortcut:
34 lf.shortcut = nn.Sequential(
35 nn.Conv2d(in_channels,out_channels,kernel_size=1,stride=stride,bias=1),
36 nn.BatchNorm2d(out_channels)
37 )
38 def forward(lf, x):
39 x_shortcut = x
40 x = lf.conv1(x)
41 x = lf.conv2(x)
42 x = lf.conv3(x)
sunday是什么意思
43 if lf.is_shortcut:
44 x_shortcut = lf.shortcut(x_shortcut)
45 x = x + x_shortcut
46 x = lf.relu(x)
47 return x
48
48
49class Resnext(nn.Module):
50 def __init__(lf,num_class,layer=[3,4,6,3]):
51 super(Resnext,lf).__init__()
52 lf.conv1 = nn.Sequential(
53 nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, bias=Fal),
54 nn.BatchNorm2d(64),
55 nn.ReLU(),
56 nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
57 )
58 lf.conv2 = lf._make_layer(64,256,1,num=layer[0])
59 lf.conv3 = lf._make_layer(256,512,2,num=layer[1])
60 lf.conv4 = lf._make_layer(512,1024,2,num=layer[2])
61 lf.conv5 = lf._make_layer(1024,2048,2,num=layer[3])
62 lf.global_average_pool = nn.AdaptiveAvgPool2d((1, 1))
63 lf.fc = nn.Linear(2048,num_class)
64 # in_features指的是输⼊的⼆维张量的⼤⼩,即输⼊的[batch_size, size]中的size。
65 # out_features指的是输出的⼆维张量的⼤⼩,即输出的⼆维张量的形状为[batch_size,output_size],当然,它也代表了该全连接层的神经元个数。
66 # 从输⼊输出的张量的shape⾓度来理解,相当于⼀个输⼊为[batch_size, in_features]的张量变换成了[batch_size, out_features]的输出张量。
67 def forward(lf, x):
68 x = lf.conv1(x)
69 x = lf.conv2(x)
70 x = lf.conv3(x)
71 x = lf.conv4(x)
andover72 x = lf.conv5(x)
73 x = lf.global_average_pool(x)
74 x = torch.flatten(x,1)
75 # 1)flatten(x,1)是按照x的第1个维度拼接(按照列来拼接,横向拼接);
76 # 2)flatten(x,0)是按照x的第0个维度拼接(按照⾏来拼接,纵向拼接);
77 # 3)有时候会遇到flatten⾥⾯有两个维度参数,flatten(x, start_dim, end_dimension),此时flatten函数执⾏的功能是将从start_dim到end_dim之间的所有维
78 # 其他的维度保持不变。例如x是⼀个size为[4,5,6]的tensor, flatten(x, 0, 1)的结果是⼀个size为[20,6]的tensor。
79 x = lf.fc(x)
80 return x
81
82 # 形成单个Stage的⽹络结构
83 def _make_layer(lf,in_channels,out_channels,stride,num):
84 layers = []
85 block_1=Block(in_channels, out_channels,stride=stride,is_shortcut=True)
86 layers.append(block_1)
87 # 该部分是将每个blocks的第⼀个残差结构保存在layers列表中。
88 for i in range(1, num): # Identity Block结构叠加; 基于[3, 4, 6, 3]
89 layers.append(Block(out_channels,out_channels,stride=1,is_shortcut=Fal))
90 # 该部分是将每个blocks的剩下残差结构保存在layers列表中,这样就完成了⼀个blocks的构造。cary
91 return nn.Sequential(*layers)
92 # 返回Conv Block和Identity Block的集合,形成⼀个Stage的⽹络结构
93
94
gripping95
96
97import time
98import torch
99import torchvision
ansforms as transforms
101import matplotlib.pyplot as plt
102
103
104def load_datat(batch_size):
105 # 下载训练集
106 train_t = torchvision.datats.CIFAR10(
107 root="data/cifar-10", train=True,
108 download=True, transform=transforms.ToTensor()
109 # transforms.ToTensor()的操作对象有PIL格式的图像以及numpy(即cv2读取的图像也可以)这两种。对象不能是tensor格式的,因为是要转换为tensor的110 )
111 # 下载测试集
112 test_t = torchvision.datats.CIFAR10(
113 root="data/cifar-10", train=Fal,
113 root="data/cifar-10", train=Fal,
114 download=True, transform=transforms.ToTensor()
115 )
116 train_iter = torch.utils.data.DataLoader(
117 train_t, batch_size=batch_size, shuffle=True, num_workers=0
118 # 该接⼝主要⽤来将⾃定义的数据读取接⼝的输出或者PyTorch已有的数据读取接⼝的输⼊按照batch size封装成Tensor,后续只需要再包装成Variable即可119 # shuffle 将训练模型的数据集进⾏打乱的操作
120 # num_workers,从注释可以看出这个参数必须⼤于等于0,0的话表⽰数据导⼊在主进程中进⾏,其他⼤于0的数表⽰通过多个进程来导⼊数据,可以加快121 )
122 test_iter = torch.utils.data.DataLoader(
123 test_t, batch_size=batch_size, shuffle=True, num_workers=0
124 )
125 return train_iter, test_iter
126
127# 训练模型
128def train(net, train_iter, criterion, optimizer, num_epochs, device, num_print, lr_scheduler=None, test_iter=None):
129 ain()
130 record_train = list()
131 # 记录每⼀Epoch下训练集的准确率
132 # List() ⽅法⽤于将元组转换为列表。
133 record_test = list()
134
135 for epoch in range(num_epochs):
德文翻译器
136 print("========== epoch: [{}/{}] ==========".format(epoch + 1, num_epochs))
137 total, correct, train_loss = 0, 0, 0
138 start = time.time()
139
140 for i, (X, y) in enumerate(train_iter):
141 # enumerate就是枚举的意思,把元素⼀个个列举出来,第⼀个是什么,第⼆个是什么,所以他返回的是元素以及对应的索引。
142 device = torch.device("cuda:0" if torch.cuda.is_available() el "cpu")
143 X, y = X.to(device), y.to(device)
144 output = net(X)
145 loss = criterion(output, y) # 计算LOSS
146
147 _grad() # 梯度归零
148 loss.backward() # 反向传播
149 optimizer.step() # 更新参数
150
151 train_loss += loss.item()
152 total += y.size(0)
153 correct += (output.argmax(dim=1) == y).sum().item() # 累积预测正确的样本数
154 # output.argmax(dim=1) 返回指定维度最⼤值的序号,dim=1,把dim=1这个维度的,变成这个维度的最⼤值的index
155 # 即 dim=1是取每⼀列最⼤值的下标,dim=2是取每⼀⾏最⼤值的下标
156 train_acc = 100.0 * correct / total
157
158 if (i + 1) % num_print == 0:
159 print("step: [{}/{}], train_loss: {:.3f} | train_acc: {:6.3f}% | lr: {:.6f}" \
160 .format(i + 1, len(train_iter), train_loss / (i + 1), \
161 train_acc, get_cur_lr(optimizer)))
162
163
164 if lr_scheduler is not None:
165 # 调整梯度下降算法的学习率
166 lr_scheduler.step()
167 # 输出训练的时间
168 print("--- cost time: {:.4f}s ---".format(time.time() - start))
169
170 if test_iter is not None: # 判断测试集是否为空 (注意这⾥将调⽤test函数)
171 record_test.append(test(net, test_iter, criterion, device)) # 每训练⼀个Epoch模型,使⽤测试集进⾏测试模型的准确度
172 record_train.append(train_acc)
173 # append() ⽅法⽤于在列表末尾追加新的对象。
174 # 返回每⼀个Epoch下测试集和训练集的准确率
175 return record_train, record_test
176
177# 验证模型
178def test(net, test_iter, criterion, device):
178def test(net, test_iter, criterion, device):
179 total, correct = 0, 0
180 net.eval()# 测试模式
181
182 _grad():
183 print("*************** test ***************")
184 for X, y in test_iter:
185 X, y = X.to(device), y.to(device)# CPU or GPU运⾏
186
187 output = net(X) # 计算输出
188 loss = criterion(output, y) # 计算损失
189
190 total += y.size(0) # 计算测试集总样本数
191 correct += (output.argmax(dim=1) == y).sum().item() # 计算测试集预测准确的样本数
192
193 test_acc = 100.0 * correct / total # 测试集准确率
194
195 # 输出测试集的损失
196 print("test_loss: {:.3f} | test_acc: {:6.3f}%" \
197 .format(loss.item(), test_acc))
198 print("************************************\n")
199
200 # 训练模式(因为这⾥是因为每经过⼀个Epoch就使⽤测试集⼀次,使⽤测试集后,进⼊下⼀个Epoch前将模型重新置于训练模式)201 ain()
202
203 return test_acc
204
205
206# 返回学习率lr的函数
207def get_cur_lr(optimizer):
208 for param_group in optimizer.param_groups:
209 return param_group['lr']
210
211
212# 画出每⼀个Epoch下测试集和训练集的准确率
213def learning_curve(record_train, record_test=None):
214 plt.style.u("ggplot")
215 # 画图⼯具:blog.csdn/viviliving/article/details/107690844
216 plt.plot(range(1, len(record_train) + 1), record_train, label="train acc")
217 # plt.plot的⽤法 /p/258106097
218 if record_test is not None:
219 plt.plot(range(1, len(record_test) + 1), record_test, label="test acc")
220
221 plt.legend(loc=4)
222 # loc:图例位置
223 plt.title("learning curve")
224 icks(range(0, len(record_train) + 1, 5))
225 icks(range(0, 101, 5))
226 plt.xlabel("epoch")
227 plt.ylabel("accuracy")
228
229 plt.show()
230
231
232import torch.optim as optim
233
234
235BATCH_SIZE = 128 # 批⼤⼩
236NUM_EPOCHS = 12 # Epoch⼤⼩
237NUM_CLASSES = 10 # 分类的个数
238LEARNING_RATE = 0.01 # 梯度下降学习率
239MOMENTUM = 0.9 # 冲量⼤⼩
240WEIGHT_DECAY = 0.0005 # 权重衰减系数
241NUM_PRINT = 100
242DEVICE = "cuda" if torch.cuda.is_available() el "cpu" # GPU or CPU运⾏
243
243
244
245def main():
246 net = Resnext(NUM_CLASSES)
247 net = (DEVICE)
248
249 train_iter, test_iter = load_datat(BATCH_SIZE) # 导⼊训练集和测试集
250
251 criterion = nn.CrossEntropyLoss() # 交叉熵损失函数损失计算器
252 # 优化器
253 optimizer = optim.SGD(
254 net.parameters(),
255 # 构建好神经⽹络后,⽹络的参数都保存在parameters()函数当中
256 lr=LEARNING_RATE,
257 momentum=MOMENTUM,
258 weight_decay=WEIGHT_DECAY,
259 nesterov=True
260 )
261 # 调整学习率 (step_size:每训练step_size个epoch,更新⼀次参数; gamma:更新lr的乘法因⼦) 262 lr_scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=5, gamma=0.1)
出纳岗位职责263
264 record_train, record_test = train(net, train_iter, criterion, optimizer, \
265 NUM_EPOCHS, DEVICE, NUM_PRINT, lr_scheduler, test_iter)
266
267 learning_curve(record_train, record_test) # 画出准确率曲线
268
269
270
271main()
272
273
下⾯是SEresnet的代码
1## 导⼊第三⽅库
2from torch import nn
3import time
4import torch
5import torchvision
ansforms as transforms
7import matplotlib.pyplot as plt
8import torch.optim as optim
9
galaga10
11# 搭建基于SENet的Conv Block和Identity Block的⽹络结构
12class Block(nn.Module):
clutch什么意思
13 def __init__(lf, in_channels, filters, stride=1, is_1x1conv=Fal):
14 super(Block, lf).__init__()
15
16 # 各个Stage中的每⼀⼤块中每⼀⼩块的输出维度,即channel(filter1 = filter2 = filter3 / 4)深邃的意思
17 filter1, filter2, filter3 = filters
18
19 lf.is_1x1conv = is_1x1conv # 判断是否是Conv Block
20 lf.relu = nn.ReLU(inplace=True) # RELU操作
21
22 # 第⼀⼩块, stride = 1(stage = 1) or stride = 2(stage = 2, 3, 4)
23 lf.conv1 = nn.Sequential(
24 nn.Conv2d(in_channels, filter1, kernel_size=1, stride=stride, bias=Fal),
25 nn.BatchNorm2d(filter1),
26 nn.ReLU()
27 )
28
29 # 中间⼩块
30 lf.conv2 = nn.Sequential(