import torch
import torch.nn.functional as F
import matplotlib.pyplot as plt
from torch import nn
from torch import optim
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, classification_report

导库

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,))]))

这里的datasets.MNIST是设置数据集,也就是在官网上下载mnist数据集,然后存放在当前目录的data子目录下,参数train是代表是否是训练集,Ture是,False不是,download代表是否在网上下载数据集,值如果为True的话,如果"./data"目录有数据集了,则不会下载,如果没有,则会下载,由于我事先下载好了数据集,这里就用False了。这里trainsform.Compose是将多个步骤整合在一起了,首先你的数据集得是Tensor(张量),Normalize是将数据正则化,说起来就稍微复杂了,可以去各平台搜索看看,总之就是将数据整合到0附近,避免过拟合。

batch_size = 256
epochs = 10
learning_rate = 0.01

train_dataloader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
test_dataloader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)

这里batch_size是批次,也就是说我们将256张图片一起放入训练,epochs是轮次(或者遍历吧),mnist的训练集图片是60000张,我们这里将60000张图片训练10次,learning_rate学习率,这里的 shuffle是是否将数据集打乱。

后面画图操作就不说了。

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()

        self.fc1 = nn.Linear(28*28, 256)
        self.fc2 = nn.Linear(256, 64)
        self.fc3 = nn.Linear(64, 10)

    def forward(self, x):
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = F.softmax(self.fc3(x), dim=1)
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()

        self.fc1 = nn.Linear(28*28, 256)
        self.fc2 = nn.Linear(256, 64)
        self.fc3 = nn.Linear(64, 10)

    def forward(self, x):
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = F.softmax(self.fc3(x), dim=1)

        return x
这个就是我们的全连接神经网络了,那些def,super的操作格式都是不变的。这里设计了三层全连接,两层relu,第三层softmax将数据整合成(0,1)之间的数


python

        return x

这个就是我们的全连接神经网络了,那些def,super的操作格式都是不变的。这里设计了三层全连接,两层relu,第三层softmax将数据整合成(0,1)之间的数

net = Net()
opt = optim.SGD(net.parameters(), lr=learning_rate, momentum=0.9)  # 返回权值 w1,b1,w2,b2,w3,b3
train_loss = []
all_train_loss = []
num = 0
for epoch in range(epochs):
    for batch_idx, (x, y) in enumerate(train_dataloader):
        x = x.view(x.size(0), 28*28)
        out = net(x).to(float)
        y_onehot = F.one_hot(y)
        y_onehot = y_onehot.to(float)
        loss = F.mse_loss(out, y_onehot)

        # loss = loss.to(torch.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())

模型建好了就该训练了,先实例化,定义优化器,直接训练,这里注意,mnist数据集的shape是[batch_size, 1, 28, 28]的,而我们全连接要的数据集是二维的,所以数据的数据要转换,这里用view(),而x.size(0)就是这个batch_size,-1就是剩下的相乘。还有这里我们要用one_hot编码去找突出的哪个值,也就是找010101这类数据里的1,通过F.mse_loss()平均损失去计算,你也可以用其他的函数,然后就是常规操作了,梯度清零,计算,更新,我们这里最后是按10各loss打印一次结果。

# 模型评估
y_all = []
pred_all = []
total_correct = 0
for x, y in test_dataloader:
    x = x.view(x.size(0), 28*28)
    out = net(x).to(torch.float32)
    pred = out.argmax(dim=1)
    y_all.extend(y.numpy())
    pred_all.extend(pred.numpy())

    y_accuracy = accuracy_score(y_all, pred_all)
    y_precision = precision_score(y_all, pred_all, average='weighted')
    y_recall = recall_score(y_all, pred_all, average='weighted')
    y_f1 = f1_score(y_all, pred_all, average='weighted')

print("[test] accuracy:{:.4f} precision:{:.4f} recall:{:.4f} f1:{:.4f}".format(y_accuracy, y_precision, y_recall, y_f1))
print(classification_report(y_all, pred_all))

模型评估跟训练差不多,因为我们用的是sklearn的方法,注意将数据转换成numpy类型的。

就是这样,差不多了,废话有点多,见谅......

最后附上一张校园的图片。。。