softmax回归预测多分类问题,预测值的输出为每一个样本所属q个类别的概率,比如一个样本有三个类别,则输出可能为[0.1, 0.8, 0.1],表示该样本属于第二个类别。
花书中的softmax回归介绍相对简单,主要思想是使用softmax函数将预测值转化为值为正且和为1的概率
如在上述公式中,若O的预测值为0.1,10,0.1,那么经过softmax函数,这三个预测输出大概变为0.01,0.98,0.1,这样输出中为类别2的概率最大,据此判断预测类别为2
同时,softmax使用交叉熵作为损失函数,因为交叉熵损失更偏重于概率大的那个值,而我们只需要将输出概率大的类别作为最终类别就行。
具体代码
这里书中的load_data_fashion_mnist(batch_size)函数是使用的d2l包中的函数,但是我们已经将FashionMNIST数据集下载到本地,不用重新下载,因此安前边代码,自己重写这个函数
import d2lzh as d2l
from mxnet import autograd,nd
import mxnet as mx
from mxnet.gluon import data as gdata
import sys
def load_data_fashion_mnist(batch_size):
mnist_train = gdata.vision.FashionMNIST(root=r'C:/Users/Wu/AppData/Roaming/mxnet/datasets/fashion-mnist/',train=True)
mnist_test = gdata.vision.FashionMNIST(root=r'C:/Users/Wu/AppData/Roaming/mxnet/datasets/fashion-mnist/',train=False)
transformer = gdata.vision.transforms.ToTensor()
if sys.platform.startswith('win'):
num_workers = 0 # 表示不用额外进程来加速读取数据
else:
num_workers = 4
train_iter = gdata.DataLoader(mnist_train.transform_first(transformer), batch_size, shuffle=True,num_workers=num_workers)
test_iter = gdata.DataLoader(mnist_test.transform_first(transformer), batch_size, shuffle=False,num_workers=num_workers)
return train_iter,test_iter
#小批量数据集
batch_size = 256
train_iter, test_iter = load_data_fashion_mnist((batch_size))
# print(len(train_iter))
#使用向量表示每个样本,所以将二维的变成一维的
num_inputs = 784 #28*28回归权重
num_outputs = 10 #10个类别,偏差参数
w = nd.random.normal(scale=0.01, shape=(num_inputs,num_outputs),ctx=mx.gpu())
b = nd.zeros(num_outputs,ctx=mx.gpu())
w.attach_grad()
b.attach_grad()
#定义softmax函数,只是把矩阵进行指数变换
#输入行为样本数,列为输出个数;输出每一行和为一,代表这个样本属于一个类别的概率
def softmax(x):
x_exp = x.exp()
partition = x_exp.sum(axis=1, keepdims=True)#1为行求和
return x_exp / partition #广播机制
#定义模型
def net(x):
return softmax(nd.dot(x.reshape((-1,num_inputs)),w) + b)
y_hat = nd.array([[0.1,0.3,0.6],[0.3,0.2,0.5]])
y = nd.array([0,2],dtype = 'int32')
#示例pick函数
print(nd.pick(y_hat,y))
#损失函数
def cross_entropy(y_hat,y):
return -nd.pick(y_hat,y).log()
#分类准确率:正确预测数量与总预测数量之比
def accuracy(y_hat, y):
#y_hat.argmax(axis=1)返回每行最大的元素的索引,mean取值为1的占总数的比
return (y_hat.argmax(axis=1) == y.astype('float32')).mean().asscalar()#返回一个NDArray
#示例
print((y_hat.argmax(axis=1) == y.astype('float32')))
print(accuracy(y_hat,y))
#评价模型net在数据集上的精确度
def evaluate_accuracy(data_iter, net):
#分布准确的数量除以总数
acc_sum, n = 0.0, 0
for x, y in data_iter:
x = x.copyto(mx.gpu())
y = y.copyto(mx.gpu())
y = y.astype('float32')
acc_sum += (net(x).argmax(axis=1) == y).sum().asscalar()
n += y.size
return acc_sum / n
#随机初始变量,所以此时精度应该接近0.1
print(evaluate_accuracy(test_iter,net))
num_epochs, lr = 5, 0.1
def train_ch3(net, train_iter, test_iter, loss, num_epochs, batch_size, params=None, lr=None, trainer=None):
for epoch in range(num_epochs):
# 总的损失# 总的准确率
train_loss_sum , train_acc_sum, n = 0.0, 0.0, 0
for X, y in train_iter:
X = X.copyto(mx.gpu())
y = y.copyto(mx.gpu())
with autograd.record():
y_hat = net(X)
los = loss(y_hat, y).sum()
# 求梯度
los.backward()
if trainer is None:
# 小批量随机梯度下降
d2l.sgd(params, lr, batch_size)
else:
trainer.step(batch_size)
train_loss_sum += los.asscalar()
train_acc_sum += accuracy(y_hat, y)
n += y.size
test_acc = evaluate_accuracy(test_iter,net)
print('epoch %d, loss %.4f, train acc %.3f, test acc %.3f'
% (epoch + 1, train_loss_sum / n, train_acc_sum / n,test_acc))
train_ch3(net,train_iter,test_iter,cross_entropy,num_epochs,batch_size,[w,b],lr)