CNN搭建方法原文链接:https://www.jb51.net/article/138245.htm
数据集及程序打包百度云:
https://pan.baidu.com/s/1xfqM-Dxn-ZUE7LXbOESMPg
提取码:aotu
1.mnist数据集测试
mnist数据集只是为了测试方法,效果不好,可以自己调参数,改变结构之类的。(需要注意的是自己下载的mnist数据集应该怎么建立文件进行存储然后读取)
# -*- coding: utf-8 -*-
"""
Created on Wed May 27 23:36:25 2020
@author: 小小飞在路上
"""
import torch
import torch.nn.functional as F
from collections import OrderedDict
from torch import optim
import torch.nn as nn
from torch.utils.data import DataLoader
from torchvision import transforms,datasets
# Method 1 -----------------------------------------
#这种方法比较常用,早期的教程通常就是使用这种方法
class Net1(torch.nn.Module):
def __init__(self):
super(Net1, self).__init__()
self.conv1 = torch.nn.Conv2d(1, 32, 3, 2, 2)
self.dense1 = torch.nn.Linear(32 * 7 * 7, 128)
self.dense2 = torch.nn.Linear(128, 10)
def forward(self, x):
x = F.max_pool2d(F.relu(self.conv1(x)), 2)
res= x.view(x.size(0), -1)
x = F.relu(self.dense1(res))
out = self.dense2(x)
return out,res
## Method 2 ------------------------------------------
##这种方法利用torch.nn.Sequential()容器进行快速搭建,模型的各层被顺序添加到容器中。缺点是每层的编号是默认的阿拉伯数字,不易区分。
#
class Net2(torch.nn.Module):
def __init__(self):
super(Net2, self).__init__()
self.conv = torch.nn.Sequential(
torch.nn.Conv2d(1, 32, 3, 2, 2),
torch.nn.ReLU(),
torch.nn.MaxPool2d(2))
self.dense = torch.nn.Sequential(
torch.nn.Linear(32 * 7 * 7, 128),
torch.nn.ReLU(),
torch.nn.Linear(128, 10)
)
def forward(self, x):
conv_out = self.conv(x)
res = conv_out.view(conv_out.size(0), -1)
out = self.dense(res)
return out,res
## Method 3 -------------------------------
##这种方法是对第二种方法的改进:通过add_module()添加每一层,并且为每一层增加了一个单独的名字。
#
class Net3(torch.nn.Module):
def __init__(self):
super(Net3, self).__init__()
self.conv=torch.nn.Sequential()
self.conv.add_module("conv1",torch.nn.Conv2d(1, 32, 3, 2, 2))
self.conv.add_module("relu1",torch.nn.ReLU())
self.conv.add_module("pool1",torch.nn.MaxPool2d(2))
self.dense = torch.nn.Sequential()
self.dense.add_module("dense1",torch.nn.Linear(32 * 7 * 7, 128))
self.dense.add_module("relu2",torch.nn.ReLU())
self.dense.add_module("dense2",torch.nn.Linear(128, 10))
def forward(self, x):
conv_out = self.conv(x)
res = conv_out.view(conv_out.size(0), -1)
out = self.dense(res)
return out,res
# Method 4 ------------------------------------------
#是第三种方法的另外一种写法,通过字典的形式添加每一层,并且设置单独的层名称。
class Net4(torch.nn.Module):
def __init__(self):
super(Net4, self).__init__()
self.conv = torch.nn.Sequential(
OrderedDict(
[
("conv1", torch.nn.Conv2d(1, 32, 3, 2, 2)),
("relu1", torch.nn.ReLU()),
("pool", torch.nn.MaxPool2d(2))
]
))
self.dense = torch.nn.Sequential(
OrderedDict([
("dense1", torch.nn.Linear(32 * 7 * 7, 128)),
("relu2", torch.nn.ReLU()),
("dense2", torch.nn.Linear(128, 10))
])
)
def forward(self, x):
conv_out = self.conv(x)
res = conv_out.view(conv_out.size(0), -1)
out = self.dense(res)
return out,res
if __name__=="__main__":
EPOCH = 1 # train the training data n times, to save time, we just train 1 epoch
batch_size = 64
LR = 0.001 # learning rate
DOWNLOAD_MNIST = False
data_tf = transforms.Compose(
[transforms.ToTensor(),
transforms.Normalize([0.5], [0.5])])
# 数据集的下载器
train_dataset = datasets.MNIST(
root='./data', train=True, transform=data_tf)
test_dataset = datasets.MNIST(root='./data', train=False, transform=data_tf)
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)
#测试四种方法
CNN=[Net1(),Net2(),Net3(),Net3()]
name=['Net1','Net2','Net3','Net4']
loss_func=nn.CrossEntropyLoss()
i=0
for cnn in CNN:
optimizer=optim.Adam(cnn.parameters(),lr=LR)
print('method:',name[i])
for epoch in range(2):
train_loss = 0.
train_acc = 0.
for step, (b_x, b_y) in enumerate(train_loader): # gives batch data, normalize x when iterate train_loader
output = cnn(b_x.float())[0] # cnn output
loss = loss_func(output, b_y.long()) # cross entropy loss
train_loss += loss.item()
pred = torch.max(output, 1)[1]
train_correct = (pred == b_y).sum()
train_acc += train_correct.item()
optimizer.zero_grad() # clear gradients for this training step
loss.backward() # backpropagation, compute gradients
optimizer.step() # apply gradients
print('Epoch: {:} |Train Loss: {:.6f} |Acc: {:.6f}'.format(epoch+1,train_loss / (len(
train_loader)), train_acc / (len(train_loader))))
cnn.eval()
eval_loss = 0.
eval_acc = 0.
for batch_x, batch_y in test_loader:
output_te = cnn(batch_x.float())[0]
loss_te = loss_func(output_te, batch_y)
eval_loss += loss_te.item()
pred_te = torch.max(output_te, 1)[1]
num_correct = (pred_te == batch_y).sum()
eval_acc += num_correct.item()
print('Test Loss: {:.6f}, Acc: {:.6f}'.format(eval_loss / (len(
test_loader)), eval_acc / (len(test_loader))))
i+=1
2.自己数据集测试
# -*- coding: utf-8 -*-
"""
Created on Tue Jun 9 12:03:08 2020
@author: 小小飞在路上
"""
import torch
import numpy as np
import pandas as pd
from torch.utils.data import DataLoader
from sklearn.utils import shuffle
from sklearn.model_selection import train_test_split
from torch.utils.data import Dataset
from torch import optim
import torch.nn as nn
import torch.nn.functional as F
from collections import OrderedDict
#读取自己数据需要增加这一部分
class data_loader(Dataset):
def __init__(self, samples, labels, t):
self.samples = samples
self.labels = labels
self.T = t
def __getitem__(self, index):
sample, target = self.samples[index], self.labels[index]
if self.T:
return self.T(sample), target
else:
return sample, target
def __len__(self):
return len(self.samples)
# Method 1 ------------------------------------------
#这种方法比较常用,早期的教程通常就是使用这种方法。
class Net1(torch.nn.Module):
def __init__(self):
super(Net1, self).__init__()
self.conv1 = torch.nn.Conv2d(1, 16, [1,3], 1, [1,2])
self.dense1 = torch.nn.Linear(16 * 1 * 12, 128)
self.dense2 = torch.nn.Linear(128, 12)
def forward(self, x):
x = F.max_pool2d(F.relu(self.conv1(x)), 2)
res= x.view(x.size(0), -1)
x = F.relu(self.dense1(res))
out = self.dense2(x)
return out,res
# Method 2 ------------------------------------------
#这种方法利用torch.nn.Sequential()容器进行快速搭建,模型的各层被顺序添加到容器中。缺点是每层的编号是默认的阿拉伯数字,不易区分。
class Net2(torch.nn.Module):
def __init__(self):
super(Net2, self).__init__()
self.conv = torch.nn.Sequential(
torch.nn.Conv2d(1, 16, [1,3], 1, [1,2]),
torch.nn.ReLU(),
torch.nn.MaxPool2d(2))
self.dense = torch.nn.Sequential(
torch.nn.Linear(16 * 1 * 12, 128),
torch.nn.ReLU(),
torch.nn.Linear(128, 12)
)
def forward(self, x):
conv_out = self.conv(x)
res = conv_out.view(conv_out.size(0), -1)
out = self.dense(res)
return out,res
# Method 3 -------------------------------
#这种方法是对第二种方法的改进:通过add_module()添加每一层,并且为每一层增加了一个单独的名字。
class Net3(torch.nn.Module):
def __init__(self):
super(Net3, self).__init__()
self.conv=torch.nn.Sequential()
self.conv.add_module("conv1",torch.nn.Conv2d(1, 16, [1,3], 1, [1,2]))
self.conv.add_module("relu1",torch.nn.ReLU())
self.conv.add_module("pool1",torch.nn.MaxPool2d(2))
self.dense = torch.nn.Sequential()
self.dense.add_module("dense1",torch.nn.Linear(16 * 1 * 12, 128))
self.dense.add_module("relu2",torch.nn.ReLU())
self.dense.add_module("dense2",torch.nn.Linear(128, 12))
def forward(self, x):
conv_out = self.conv(x)
res = conv_out.view(conv_out.size(0), -1)
out = self.dense(res)
return out,res
# Method 4 ------------------------------------------
#是第三种方法的另外一种写法,通过字典的形式添加每一层,并且设置单独的层名称。
class Net4(torch.nn.Module):
def __init__(self):
super(Net4, self).__init__()
self.conv = torch.nn.Sequential(
OrderedDict(
[
("conv1", torch.nn.Conv2d(1, 16, [1,3], 1, [1,2])),
("relu1", torch.nn.ReLU()),
("pool", torch.nn.MaxPool2d(2))
]
))
self.dense = torch.nn.Sequential(
OrderedDict([
("dense1", torch.nn.Linear(16 * 1 * 12, 128)),
("relu2", torch.nn.ReLU()),
("dense2", torch.nn.Linear(128, 12))
])
)
def forward(self, x):
conv_out = self.conv(x)
res = conv_out.view(conv_out.size(0), -1)
out = self.dense(res)
return out,res
if __name__=="__main__":
#参数设置
EPOCH = 1
batch_size = 128
LR = 0.001
url = 'data.csv'
data = pd. read_csv(url, sep=',',header=None)
data=np.array(data)
data=shuffle(data)
X1=data[:,:23]
Y1=data[:,23]
labels1=np.asarray(pd.get_dummies(Y1),dtype=np.int8)
Y=np.argmax(labels1,axis=1)
X_train1,X_test1,Y_train1,Y_test1=train_test_split(X1,Y,test_size=0.001,random_state=20)
X_train=X_train1.reshape((-1,1,1,23))
X_test=X_test1.reshape((-1,1,1,23))
#增加读取数据代码的使用
transform = None
train_dataset = data_loader(X_train, Y_train1, transform)
test_dataset = data_loader(X_test, Y_test1, transform)
#别的部分正常使用就行
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)
#测试四种方法
CNN=[Net1(),Net2(),Net3(),Net3()]
name=['Net1','Net2','Net3','Net4']
loss_func=nn.CrossEntropyLoss()
i=0
for cnn in CNN:
optimizer=optim.Adam(cnn.parameters(),lr=LR)
print('method:',name[i])
for epoch in range(3):
train_loss = 0.
train_acc = 0.
for step, (b_x, b_y) in enumerate(train_loader): # gives batch data, normalize x when iterate train_loader
output = cnn(b_x.float())[0] # cnn output
loss = loss_func(output, b_y.long()) # cross entropy loss
train_loss += loss.item()
pred = torch.max(output, 1)[1]
train_correct = (pred == b_y).sum()
train_acc += train_correct.item()
optimizer.zero_grad() # clear gradients for this training step
loss.backward() # backpropagation, compute gradients
optimizer.step() # apply gradients
print('Epoch: {:} |Train Loss: {:.6f} |Acc: {:.6f}'.format(epoch,train_loss / (len(
X_train)), train_acc / (len(X_train))))
cnn.eval()
eval_loss = 0.
eval_acc = 0.
for batch_x, batch_y in test_loader:
output_te = cnn(batch_x.float())[0]
loss_te = loss_func(output_te, batch_y)
eval_loss += loss_te.item()
pred_te = torch.max(output_te, 1)[1]
num_correct = (pred_te == batch_y).sum()
eval_acc += num_correct.item()
print('Test Loss: {:.6f}, Acc: {:.6f}'.format(eval_loss / (len(
X_test)), eval_acc / (len(X_test))))
i+=1
结果
一般功能函数和测试程序分开比较方便,也顺眼,我为了测试的的人方便,自己也不用额外说明才整体写一块(自己的程序不建议这样,会显得很乱)。