import torch
import torch.nn.functional as F
import matplotlib.pyplot as plt
from torch import nn
from torch import optim
from torch.utils.data import DataLoader
from torchvision import datasets, transforms
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, classification_report
import warnings
warnings.filterwarnings('ignore')
batch_size = 256
epochs = 10
learning_rate = 0.01
train_dataset = datasets.MNIST('./data', train=True, download=False, transform=transforms.Compose([
transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,))]))
test_dataset = datasets.MNIST('./data', train=False, download=False, transform=transforms.Compose([
transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,))]))
train_dataloader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
test_dataloader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)常规操作就不说了,导库加载数据,说明一下warnings,这里就是去除一些不会影响运行的警告。
def plot_curve(data, name):
plt.plot(range(len(data)), data, color='blue')
plt.legend([name], loc='upper right')
plt.xlabel('step')
plt.ylabel('value')画图工具
class Net(nn.Module):
'''公式 out = (i-k+2p+1)/s, conv满5往上取整, pooling往下取整'''
def __init__(self):
super(Net, self).__init__()
self.conv = nn.Sequential(
nn.Conv2d(1, 32, kernel_size=3, stride=1, padding=0), # [256, 1, 28, 28] => [256, 32, , ]
nn.ReLU(),
nn.MaxPool2d(kernel_size=2, stride=2),
nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=0),
nn.ReLU(),
nn.MaxPool2d(kernel_size=2, stride=2),
)
self.fc = nn.Sequential(
nn.Linear(64*5*5, 32),
nn.ReLU(),
nn.Linear(32, 16),
nn.ReLU(),
nn.Linear(16, 10),
# nn.Softmax(dim=1)
)
def forward(self, x):
x = self.conv(x)
# x = torch.nn.functional.adaptive_avg_pool2d(x, (1, 1))
# x = x.view(x.size(0), -1)
x = x.view(x.size(0), 64*5*5)
x = self.fc(x)
return x这是一个简单的卷积网络,很简单,一层卷积一层池化,这里也就两层卷积,计算卷积后图像的大小公式:公式 out = (i-k+2p+1)/s, conv满5往上取整, pooling往下取整,就找这个算,得到的输出就是下面全连接的输入,在传入前馈后,经过了卷积后的图像依然是[b, , , ]四维的,而全连接要的是二维,所以还是要转换一下,不然要报错。就像我上面的参数,卷积后为[256, 64, 5, 5],转二维后[256, 64*5*5]
net = Net()#.to(device)
criteon = nn.CrossEntropyLoss()#.to(device)
opt = optim.Adam(net.parameters(), lr=learning_rate)
print(net)
train_loss = []
all_train_loss = []
num = 0.0
for epoch in range(epochs):
for batch_idx, (x, y) in enumerate(train_dataloader):
# x, y = x.to(device), y.to(device)
out = net(x)
# loss = criteon(out, y)
loss = criteon(out.to(float), F.one_hot(y).to(float))
opt.zero_grad()
loss.backward()
opt.step()
all_train_loss.append(loss.item())
num += 1
if batch_idx % 10 == 0:
print(epoch, batch_idx, loss.item())
train_loss.append(loss.item() / num)接下来就是实例化模型了,这里训练模型如果有GPU的可以传到GPU上,不过运算完记得传回CPU,跟之前全连接没多大区别,只不过这里我用了nn.CrossEntropyLoss,这是交叉熵函数,看过之前全连接的应该能注意到上面全连接最后一层我没有加softmax,这个nn.CrossEntropyLoss相当于torch.nn.LogSoftmax和torch.nn.NLLLoss,源码里的解释有说明
而为什么又要这样用呢,首先使用softmax()最后计算精度上会有偏差,softmax会进行指数操作,而x值过大或者过小时会造成exp(x)超过float的范围,LogSoftmax解决了上溢或者下溢的问题,而torch. nn.CrossEntropyLoss()包含这两种函数,这样既解决了上下溢,又不用再使用one_hot编码。
剩下的代码就更全连接大差不差了,相信认真看的肯定能懂,毕竟还是很好理解的。
不多说了,还有下一个实现,期待下次更新吧。。。