1、点集分类
-
机器学习中的监督学习主要分为回归问题和分类问题,本文讲一下关于简单点集分类的神经网络解决方法。
-
分类问题所预测的结果就是离散的类别 c 这时 输入变量可以是离散的,也可以是连续的,而监督学习从数据中学习→个分类模型或 者分类决策函数,它被称为分类器( c1assifier )。 分类器对新的输入进行输出预测,这 个过程即称为分类( c1assification )。
-
思路是先拟合决策边界(回归问题)(这里的决策边界 不局限于线性,还可以是多项式),在建立这个边界和分类概率的关系,从而得到二分 类情况下的概率。
2、示例一
# encoding: utf-8
import torch
import torch.nn as nn
import numpy as np
import matplotlib.pyplot as plt
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
# 输入为一个点(xi,yi)二维,输出为判断点的标签(0或1)一维
self.linear = nn.Linear(2, 1)
# 将输出经过sigmoid激活函数映射为概率,并取概率大的标签
self.sm = nn.Sigmoid()
def forward(self, x):
x = self.linear(x)
x = self.sm(x)
return x
if __name__ == '__main__':
"""构建数据集"""
data = torch.ones(100, 2) # 制造100个随机点(xi,yi)所需数据
# point1 point2 围绕指定点产生服从正态分布的个数个数字,每个数字用一个二维坐标表示(x,y)
point1 = torch.normal(1 * data, 1) # 点类1:分布在1附近的正态分布(标准差为1)
target1 = torch.zeros(100) # point1 100个点的标签设为0
point2 = torch.normal(-1 * data, 1) # 点类2:分布在-1附近的正态分布(标准差为1)
target2 = torch.ones(100) # point1 100个点的标签设为1
# 将两类点和标签放在一起,方便训练
point = torch.cat((point1, point2), 0) # 第二个参数为 0 按行合并,为1按列合并
target = torch.cat((target1, target2), 0)
# 打印数据
plt.scatter(point1[:, 0], point1[:, 1], c='red') # 点1的散点图图,红点
plt.scatter(point2[:, 0], point2[:, 1], c='blue') # 点2的散点图图,蓝点
plt.show()
"""构建用于分类的神经网络"""
net = Net()
"""进行训练"""
# 学习效率为0.01的 SGD 优化器
optimizer = torch.optim.SGD(net.parameters(), lr=0.01)
loss_fuc = nn.BCELoss() # 二分类用的损失函数
epochs = 100
# 训练步骤与前面大致相同,不在细述
for epoch in range(epochs):
out_target = net(point)
loss = loss_fuc(out_target, target)
optimizer.zero_grad()# 优化前使前一次梯度归0
loss.backward()# 损失函数反向传递
optimizer.step()# 执行优化
if epoch % 20 == 0:
print('epoch: {} | loss: {:.3f}'.format(epoch, loss))
"""以概率0.5为分界线标记网络划分点"""
plt.scatter(point1[:, 0], point1[:, 1], c='red') # 点1的散点图图,红点
plt.scatter(point2[:, 0], point2[:, 1], c='blue') # 点2的散点图图,蓝点
out_target = net(point)#预测属于哪个分类的概率,200个,
for i in range(len(out_target)):
if out_target[i] >= 0.5: # 将预测概率大于0.5的点标绿
plt.scatter(point[i][0], point[i][1], c='green')
plt.show()
3、示例二
用PyTorch的逻辑回归实现图像分类
数据集来自MNIST手写数字数据库。它由手写数字(0到9)的28px乘28px灰度图像以及每个图像的标签组成。
(1)导入torch、torchvision和MNIST
import torch
import torchvision
from torchvision.datasets import MNIST
datasets = MNIST(root="data/",download=True)
def show_one_dataset_image(datasets,i):
"""查看数据集中的某个图像"""
image,label = datasets[i]
plt.imshow(image)
print("label:",label.item())
这个数据集有60000张图片,可以用来训练模型。还有一个10,000个图像的附加测试集,可以通过将train = False传递给MNIST类来创建。
该图像是PIL.Image.Image类的对象,由28x28图像和标签组成。PIL是Python成像库Pillow。
先看数据集里的几个图片:
PyTorch无法直接处理图像,需要将图像转换成tensor。
import torchvision.transforms as transforms
def plt_tensor_img(datasets,i):
"""使用tensor画出图像"""
img_tensor,label = datasets[i]
print(img_tensor.shape,label)
# 颜色映射(cmap ='gray'),表示我们想要查看灰度图像。
plt.imshow(img_tensor[0],cmap='gray')
PyTorch数据集允许我们指定一个或多个转换函数,这些函数在加载时应用于图像。
torchvision.transforms包含许多这样的预定义函数,我们将使用ToTensor变换将图像转换为PyTorchtensor。
现在图像转换为1x28x28的tensor。第一个维度用于跟踪颜色通道。由于MNIST数据集中的图像是灰度级的,因此只有一个通道。 其他数据集具有彩色图像,在这种情况下有3个通道:红色,绿色和蓝色(RGB)。
(2)划分数据集
a、
在构建真实世界的机器学习模型时,将数据集分成3个部分是很常见的:
训练集:用于训练模型,即计算损失并使用梯度下降调整模型的权重
验证集:用于在训练时评估模型,调整超参数(学习率等)并选择最佳版本的模型
测试集:用于比较不同的模型或不同类型的建模方法,并报告模型的最终准确性
在MNIST数据集中,有60,000个训练图像和10,000个测试图像。测试集是标准化的,以便不同的研究人员可以针对同一组图像报告其模型的结果。
由于没有预定义的验证集,我们必须手动将60,000个图像拆分为训练和验证数据集
def split_indices(n,val_pct):
""" 划分验证集和训练集
split_indices随机地混洗数组索引0,1,... n-1,并从中为验证集分离出所需的部分。"""
n_val = int(val_pct*n)
# 混洗索引
idxs = np.random.permutation(n)
print(idxs)
return idxs[n_val:],idxs[:n_val]
split_indices随机地混洗数组索引0,1,... n-1,并从中为验证集分离出所需的部分。
在创建验证集之前对索引进行混洗是很重要的,因为训练图像通常由目标标签排序,即0s的图像,然后是1s的图像,接着是2s的图像,依此类推。
如果我们仅通过选择最后20%的图像来选择20%的验证集,则验证集将仅包括8s和9s的图像,而训练集将不包含8s和9s的图像,这样就不可能训练一个好的模型。
b、
现在可以使用SubsetRandomSampler为每个创建PyTorch数据加载器,SubsetRandomSampler从给定的索引列表中随机采样元素,同时创建batch数据。
from torch.utils.data.sampler import SubsetRandomSampler
from torch.utils.data.dataloader import DataLoader
# PyTorch数据集允许我们指定一个或多个转换函数,这些函数在加载时应用于图像。
# torchvision.transforms包含许多这样的预定义函数,
#我们将使用ToTensor变换将图像转换为PyTorchtensor。
datasets = MNIST(root="data/",train=True,transform=transforms.ToTensor(), download=True)
train_indices,val_indices = split_indices(len(datasets),0.2)
print(len(train_indices),len(val_indices))
batch_size = 100
# 使用SubsetRandomSampler为每个创建PyTorch数据加载器
# SubsetRandomSampler从给定的索引列表中随机采样元素,同时创建batch数据。
train_sampler = SubsetRandomSampler(train_indices)
train_loader = DataLoader(datasets,batch_size,sampler=train_sampler)
val_sampler = SubsetRandomSampler(val_indices)
val_loader = DataLoader(datasets,batch_size,sampler=val_sampler)
(3)建模
我们可以使用nn.Linear来创建模型,而不是手动定义和初始化矩阵
由于nn.Linear期望每个训练示例都是一个tensor,因此每个1x28x28图像tensor需要在传递到模型之前被展平为大小为784(28 * 28)的tensor
每个图像的输出是大小为10的tensor,tensor的每个元素表示特定目标标记(即0到9)的概率。 图像的预测标签只是具有最高概率的标签
import torch.nn as nn
class MnistModel(nn.Module):
def __init__(self):
super().__init__()
self.linear = nn.Linear(input_size,num_classes)
def forward(self,xb):
# 将图像打平,维度为(1,784
xb = xb.reshape(-1, 784)
out = self.linear(xb)
return out
在__init__构造函数方法中,我们使用nn.Linear实例化权重和偏差。
在我们将一批输入传递给模型时调用的forward方法中,我们将输入tensor展平,然后将其传递给self.linear。
xb.reshape(-1,28 * 28)向PyTorch指明,我们想要具有两个维度的xbtensor的视图,其中沿第二维度的长度是28 * 28(即784)。
.reshape的一个参数可以设置为-1(在这种情况下是第一个维度),让PyTorch根据原始tensor的形状自动计算出来。
请注意,模型不再具有.weight和.bias属性(因为它们现在位于.linear属性中),但它确实有一个.parameters方法,该方法返回包含权重和偏差的列表,并且可以使用PyTorch优化器。
我们的新自定义模型可以像以前一样使用。 让我们看看它是否有效。
(4)softmax函数
# 虽然很容易实现softmax函数,我们将使用PyTorch中提供的实现,因为它适用于多维tensor(在我们的例子中是输出行列表)。
from torch.nn import functional as F
最后,我们可以通过简单地选择每个输出行中具有最高概率的元素的索引来确定每个图像的预测标签。
这是使用torch.max完成的,它返回最大元素和沿tensor的特定维度的最大元素的索引。
(5)评估度量和损失函数
一种自然的方法是找到正确预测的标签百分比,即预测的准确性。
==运算符执行具有相同形状的两个tensor的逐元素比较,并返回相同形状的tensor,对于不相等的元素包含0,对于相等的元素包含1。
将结果传递给torch.sum会返回正确预测的标签数。最后,我们除以图像总数来获得准确性。
虽然精度是我们(人类)评估模型的好方法,但它不能用作使用梯度下降优化模型的损失函数,原因如下:
这不是一个可区分的功能。torch.max和==都是非连续和非可微操作,因此我们无法使用精度来计算重量和偏差的梯度
它没有考虑模型预测的实际概率,因此无法为渐进式改进提供足够的反馈
由于这些原因,准确性是分类的一个很好的评估指标,但不是一个好的损失函数。 分类问题常用的损失函数是交叉熵,其具有以下公式:
对于每个输出行,选择正确标签的预测概率。例如。如果图像的预测概率是[0.1,0.3,0.2,...]并且正确的标签是1,我们选择相应的元素0.3并忽略其余的
然后,取所选概率的对数。如果概率很高,即接近1,则其对数是非常小的负值,接近于0。如果概率低(接近0),则对数是非常大的负值。我们还将结果乘以-1,结果是预测不良的损失的大正值 最后,获取所有输出行的交叉熵的平均值,以获得一批数据的总体损失
与准确度不同,交叉熵是一种连续且可微分的函数,它还为模型中的渐进改进提供了良好的反馈(正确标签导致较低损失的概率略高)。这使它成为损失函数的一个很好的选择。
PyTorch提供了一种有效且张量友好的交叉熵实现,作为torch.nn.functionalpackage的一部分。
此外,它还在内部执行softmax,因此我们可以直接传递模型的输出而不将它们转换为概率。
由于交叉熵是在所有训练样本上平均的正确标签的预测概率的负对数,因此一种解释结果数的方法,例如,2.23是e ^ -2.23,平均值约为0.1,作为正确标签的预测概率。降低损失,改善模型。
(6)优化
我们将使用optim.SGD优化器在训练期间更新权重和偏差,但学习率更高,为1e-3。
batch大小,学习率等参数需要在训练机器学习模型时提前选取,并称为超参数。
选择正确的超参数对于在合理的时间内训练准确的模型至关重要,并且是研究和实验的活跃领域。随意尝试不同的学习率,看看它如何影响训练过程。
(7)训练模型
训练过程几乎与线性回归相同。但是,我们将增加我们之前定义的拟合函数,以使用每个epoch末尾的验证集来评估模型的准确性和损失。
我们首先定义一个函数loss_batch:
计算一批数据的损失
如果提供了优化程序,则可以选择执行梯度下降更新步骤
可选地使用预测和实际目标来计算度量(例如,准确度)
def loss_batch(model,loss_func,xb,yb,opt=None,metric=None):
"""
增加我们之前定义的拟合函数,以使用每个epoch末尾的验证集来评估模型的准确性和损失。
计算一批数据的损失如果提供了优化程序,则可以选择执行梯度下降更新步骤
可选地使用预测和实际目标来计算度量(例如,准确度)
:param model:
:param loss_func:
:param xb:
:param yb:
:param opt:
:param mertic:
:return:
"""
preds = model(xb)
loss=loss_func(preds,yb)#计算误差
if opt is not None:
loss.backward()#计算梯度
opt.step()#更新参数
opt.zero_grad()#重置梯度为0
metric_result = None
if metric is not None:
metric_result = metric(preds,yb)
return loss.item(),len(xb),metric_result
优化器是一个可选参数,以确保我们可以重用loss_batch来计算验证集上的损失。
我们还将batch处理的长度作为结果的一部分返回,因为它在组合整个数据集的损失/度量时非常有用。
接下来,我们定义一个函数evaluate,它计算验证集的总体损失。
def evaluate(model,loss_fn,valid_dl,metric=None):
"""
函数evaluate,它计算验证集的总体损失。
:param model:
:param loss_fn:
:param valid_dl:
:param metric:
:return:
"""
with torch.no_grad():
# 对每个批次的数据进行训练,得到误差、数据量等数据
result = [loss_batch(model,loss_fn,xb,yb,metric=metric) for xb,yb in valid_dl]
# 将三者分开
losses,nums,metrics = zip(*result)
# 数据集总大小
total = np.sum(nums)
# 所有批次的平均误差
total_loss = np.sum(np.multiply(losses,nums))
avg_loss = total_loss / total
avg_metric = None
if metric is not None:
tot_metric = np.sum(np.multiply(metrics,nums))
avg_metric = tot_metric / total
return avg_loss,total,avg_metric
我们还需要重新定义精确度以直接操作整批输出,以便我们可以将其用作拟合度量。
请注意,我们不需要将softmax应用于输出,因为它不会更改结果的相对顺序。
这是因为e ^ x是增加函数,即如果y1> y2,则e ^ y1> e ^ y2,并且在对值求平均值以获得softmax之后也是如此。
使用loss_batch和evaluate轻松定义拟合函数。
def fit(epochs,models,loss_fn,opt,train_dl,valid_dl,metric=None):
"""
使用loss_batch和evaluate轻松定义拟合函数
:param epoch:
:param models:
:param loss_fn:
:param opt:
:param train_dl:
:param valid_dl:
:param metric:
:return:
"""
for epoch in range(epochs):
for xb,yb in train_dl:
loss,_,_ = loss_batch(model,loss_fn,xb,yb,opt)
result = evaluate(model,loss_fn,valid_dl,metric)
val_loss ,total,val_metric = result
if metric is None:
print("Epoch[{}/{}],Loss:{:.4f}".format(epoch+1,epochs,val_loss))
else:
print("Epoch[{}/{}],Loss:{:.4f},{}:{:.4f}".format(epoch + 1, epochs, val_loss,
metric.__name__, val_metric))
我们现在准备训练模型。 让我们训练5个epoch并观察结果。
从上面的图片中可以清楚地看出,即使经过很长时间的训练,该模型也可能不会超过90%的准确度阈值。
一个可能的原因是学习率可能太高。模型的参数可能会围绕具有最低损耗的最佳参数集“弹跳”。
您可以尝试降低学习速度和训练几个epoch,看看它是否有帮助。
更可能的原因是该模型不够强大。如果你还记得我们的初始假设,我们假设输出(在这种情况下是类概率)是输入(像素强度)的线性函数,通过对权重矩阵执行矩阵乘法并添加偏差来获得。
这是一个相当弱的假设,因为图像中的像素强度和它所代表的数字之间可能实际上不存在线性关系。
虽然它对于像MNIST这样的简单数据集(使我们达到85%的准确度)工作得相当好,但我们需要更复杂的模型来捕捉图像像素和标签之间的非线性关系,以便识别日常物品,动物等复杂任务。
(8)使用单个图像进行测试
虽然到目前为止我们一直在跟踪模型的整体精度,但在一些样本图像上查看模型的结果也是一个好主意。
让我们用10000个图像的预定义测试数据集中的一些图像测试我们的模型。 我们首先使用ToTensor变换重新创建测试数据集。
def show_one_dataset_image(datasets,i):
"""查看数据集中的某个图像"""
image,label = datasets[i]
plt.imshow(image[0])
plt.show()
return image,label
def predict_image(img,model):
# img.unsqueeze只是在1x28x28张量的开始处添加另一个维度,
# 使其成为1x1x28x28张量,模型将其视为包含单个图像的批处理。
xb = img.unsqueeze(0)
yb = model(xb)
_,preds = torch.max(yb,dim=1)
return preds[0].item()
#======================================================
"""单个样本测试"""
test_datasets = MNIST(root='data/',train=False,transform=transforms.ToTensor())
image,label = show_one_dataset_image(test_datasets,0)
print('Lable:',label,',Predicted:',predict_image(image,model))
通过收集更多的训练数据,增加/减少模型的复杂性以及更改超参数,确定我们的模型表现不佳的位置可以帮助我们改进模型
(9)测试集上模型的整体损失和准确性
def show_one_dataset_image(datasets,i):
"""查看数据集中的某个图像"""
image,label = datasets[i]
plt.imshow(image[0])
plt.show()
return image,label
def predict_image(img,model):
# img.unsqueeze只是在1x28x28张量的开始处添加另一个维度,
# 使其成为1x1x28x28张量,模型将其视为包含单个图像的批处理。
xb = img.unsqueeze(0)
yb = model(xb)
_,preds = torch.max(yb,dim=1)
return preds[0].item()
#===============================================
test_datasets = MNIST(root='data/',train=False,transform=transforms.ToTensor())
test_loader = DataLoader(test_datasets,batch_size=200)
test_loss,total,test_acc= evaluate(model,loss_fn,test_loader,metric=accuracy)
print('Loss:{:.4f, Accuracy:{:.4f}'.format(test_loss,test_acc))
我们希望这与验证集上的准确度/损失相似。如果没有,我们可能需要一个更好的验证集,它具有与测试集类似的数据和分布(通常来自现实世界数据)。
(10)保存并加载模型
由于我们已经长时间训练模型并获得了合理的精度,因此将权重和偏置矩阵保存到磁盘是个好主意,这样我们可以在以后重用模型并避免从头开始重新训练。以下是保存模型的方法。
name = 'mnist-logistic.pth'
torch.save(model.state_dict(),name)
print(model.state_dict())
要加载模型权重,我们可以实例化MnistModel类的新对象,并使用.load_state_dict方法。
name = 'mnist-logistic.pth'
model_saved = MnistModel()
model_saved.load_state_dict(torch.load(name))
print(model_saved.state_dict())
验证此模型在测试集上具有与以前相同的损失和准确性。
test_loader = DataLoader(test_datasets,batch_size=200)
test_loss,total,test_acc= evaluate(model_saved,loss_fn,test_loader,metric=accuracy)
print('model validate Loss:{:.4f}, Accuracy:{:.4f}'.format(test_loss,test_acc))
3、示例二完整代码
# encoding: utf-8
"""
@author: sxp
@file: classify_torch_demo.py
@time: 2019/11/4 19:56
"""
import torch
import torchvision
from torchvision.datasets import MNIST
import matplotlib.pyplot as plt
# PyTorch无法直接处理图像,需要将图像转换成tensor。
import torchvision.transforms as transforms
import numpy as np
from torch.utils.data.sampler import SubsetRandomSampler
from torch.utils.data.dataloader import DataLoader
import torch.nn as nn
# 虽然很容易实现softmax函数,我们将使用PyTorch中提供的实现,
#因为它适用于多维tensor(在我们的例子中是输出行列表)。
from torch.nn import functional as F
def show_one_dataset_image(datasets,i,show_image=False):
"""查看数据集中的某个图像"""
image,label = datasets[i]
if show_image is not False:
plt.imshow(image[0])
plt.show()
return image,label
def plt_tensor_img(datasets,i):
"""使用tensor画出图像"""
img_tensor,label = datasets[i]
print(img_tensor.shape,label)
# 颜色映射(cmap ='gray'),表示我们想要查看灰度图像。
plt.imshow(img_tensor[0],cmap='gray')
plt.show()
def split_indices(n,val_pct):
""" 划分验证集和训练集
split_indices随机地混洗数组索引0,1,... n-1,并从中为验证集分离出所需的部分。"""
n_val = int(val_pct*n)
# 混洗索引
idxs = np.random.permutation(n)
print(idxs)
return idxs[n_val:],idxs[:n_val]
def loss_batch(model,loss_func,xb,yb,opt=None,metric=None):
"""
增加我们之前定义的拟合函数,以使用每个epoch末尾的验证集来评估模型的准确性和损失。
计算一批数据的损失如果提供了优化程序,则可以选择执行梯度下降更新步骤
可选地使用预测和实际目标来计算度量(例如,准确度)
:param model:
:param loss_func:
:param xb:
:param yb:
:param opt:
:param mertic:
:return:
"""
preds = model(xb)
loss=loss_func(preds,yb)#计算误差
if opt is not None:
loss.backward()#计算梯度
opt.step()#更新参数
opt.zero_grad()#重置梯度为0
metric_result = None
if metric is not None:
metric_result = metric(preds,yb)
return loss.item(),len(xb),metric_result
def evaluate(model,loss_fn,valid_dl,metric=None):
"""
函数evaluate,它计算验证集的总体损失。
:param model:
:param loss_fn:
:param valid_dl:
:param metric:
:return:
"""
with torch.no_grad():
# 对每个批次的数据进行训练,得到误差、数据量等数据
result = [loss_batch(model,loss_fn,xb,yb,metric=metric) for xb,yb in valid_dl]
# 将三者分开
losses,nums,metrics = zip(*result)
# 数据集总大小
total = np.sum(nums)
# 所有批次的平均误差
total_loss = np.sum(np.multiply(losses,nums))
avg_loss = total_loss / total
avg_metric = None
if metric is not None:
tot_metric = np.sum(np.multiply(metrics,nums))
avg_metric = tot_metric / total
return avg_loss,total,avg_metric
def accuracy(outputs,labels):
"""定义精确度以直接操作整批输出,以便我们可以将其用作拟合度量"""
_,preds = torch.max(outputs,dim=1)
return torch.sum(preds == labels).item() / len(preds)
def fit(epochs,models,loss_fn,opt,train_dl,valid_dl,metric=None):
"""
使用loss_batch和evaluate轻松定义拟合函数
:param epoch:
:param models:
:param loss_fn:
:param opt:
:param train_dl:
:param valid_dl:
:param metric:
:return:
"""
for epoch in range(epochs):
for xb,yb in train_dl:
loss,_,_ = loss_batch(model,loss_fn,xb,yb,opt)
result = evaluate(model,loss_fn,valid_dl,metric)
val_loss ,total,val_metric = result
if metric is None:
print("Epoch[{}/{}],Loss:{:.4f}".format(epoch+1,epochs,val_loss))
else:
print("Epoch[{}/{}],Loss:{:.4f},{}:{:.4f}".format(epoch + 1, epochs, val_loss,
metric.__name__, val_metric))
def predict_image(img,model):
# img.unsqueeze只是在1x28x28张量的开始处添加另一个维度,
# 使其成为1x1x28x28张量,模型将其视为包含单个图像的批处理。
xb = img.unsqueeze(0)
yb = model(xb)
_,preds = torch.max(yb,dim=1)
return preds[0].item()
class MnistModel(nn.Module):
def __init__(self):
super().__init__()
self.linear = nn.Linear(input_size,num_classes)
def forward(self,xb):
# 将图像打平,维度为(1,784
xb = xb.reshape(-1, 784)
out = self.linear(xb)
return out
if __name__ == '__main__':
# datasets = MNIST(root="data/",download=True)
# PyTorch数据集允许我们指定一个或多个转换函数,这些函数在加载时应用于图像。
# torchvision.transforms包含许多这样的预定义函数,我们将使用ToTensor变换将图像转换为PyTorchtensor。
datasets = MNIST(root="data/",train=True,transform=transforms.ToTensor(), download=True)
train_indices,val_indices = split_indices(len(datasets),0.2)
print(len(train_indices),len(val_indices))
batch_size = 100
# 使用SubsetRandomSampler为每个创建PyTorch数据加载器
# SubsetRandomSampler从给定的索引列表中随机采样元素,同时创建batch数据。
train_sampler = SubsetRandomSampler(train_indices)
train_loader = DataLoader(datasets,batch_size,sampler=train_sampler)
val_sampler = SubsetRandomSampler(val_indices)
val_loader = DataLoader(datasets,batch_size,sampler=val_sampler)
# 每个1x28x28图像tensor需要在传递到模型之前被展平为大小为784(28 * 28)的tensor
# 每个图像的输出是大小为10的tensor,tensor的每个元素表示特定目标标记(即0到9)的概率。
# 图像的预测标签只是具有最高概率的标签
input_size = 28 * 28
num_classes = 10
# 逻辑回归模型
# model =nn.Linear(input_size,num_classes)
# print(model.weight.shape)
# print(model.bias.shape)
# 请注意,模型不再具有.weight和.bias属性(因为它们现在位于.linear属性中),但它确实
#有一个.parameters方法,该方法返回包含权重和偏差的列表,并且可以使用PyTorch优化器。
model = MnistModel()
print("model.parameters() = ",model.parameters())
# 分类问题常用的损失函数是交叉熵
loss_fn = F.cross_entropy
# 优化
learning_rate = 0.001
opt = torch.optim.SGD(model.parameters(), lr=learning_rate)
fit(5,model,loss_fn,opt,train_loader,val_loader,accuracy)
name = 'mnist-logistic.pth'
torch.save(model.state_dict(),name)
print(model.state_dict())
model_saved = MnistModel()
model_saved.load_state_dict(torch.load(name))
print(model_saved.state_dict())
"""单个样本测试"""
test_datasets = MNIST(root='data/',train=False,transform=transforms.ToTensor())
image,label = show_one_dataset_image(test_datasets,0,False)
print('Lable:',label,',Predicted:',predict_image(image,model))
test_loader = DataLoader(test_datasets,batch_size=200)
test_loss,total,test_acc= evaluate(model_saved,loss_fn,test_loader,metric=accuracy)
print('model validate Loss:{:.4f}, Accuracy:{:.4f}'.format(test_loss,test_acc))