与第一课线性回归(linear regression)不同,softmax回归针对的是多分类的情况,即labels不再仅有0,1两个分类。
softmax通过指数运算将最后的分类转为0~1间的概率,在终于类别概率中,数值大的为预测概率。
与线性回归损失不同,softmax函数计算损失采用的是交叉熵损失(Cross Entropy),原理和公式推导可参考:https://zhuanlan.zhihu.com/p/27223959
softmax函数简单实现代码如下:
from mxnet import autograd,nd
import gluonbook as gb
%matplotlib inline
import time
import matplotlib.pyplot as plt
import sys
#读取数据
batch_size = 256
train_iter,test_iter = gb.load_data_fashion_mnist(batch_size)
#参数初始化
num_inputs = 784
num_outputs = 10
w = nd.random.normal(scale = 1,shape = (num_inputs,num_outputs))
b = nd.random.normal(num_outputs)
w.attach_grad()
b.attach_grad()
#正向传播,实现softmax运算
def softmax(x):
return nd.exp(x) / nd.exp(x).sum(axis = 1,keepdims = True)
def net(x):
return softmax(nd.dot(x.reshape((-1,num_inputs)),w) + b) #对求得的yhat执行softmax运算
def cross_entropy(y_hat,y): #定义交叉损失熵函数
return -nd.pick(y_hat,y).log()
def accuracy(yhat,y):
return (yhat.argmax(axis = 1) == y.astype('float32')).mean().asscalar() #提取yhat中每行概率最大的类别和真实值y的类别比较后的概率
def evaluate_accuracy(data_iter,net):
acc = 0
for X,y in data_iter:
acc+= accuracy(net(X),y)
return acc/len(data_iter)
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_l_sum = 0 #定义训练损失总和
train_acc_sum = 0 #定义训练精度总和
for X ,y in train_iter:
with autograd.record():
y_hat = net(X)
l = loss(y_hat,y)
l.backward()
if trainer is None:
gb.sgd(params,lr,batch_size)
else:
trainer.step(batch_size)
train_l_sum += l.mean().asscalar()
train_acc_sum += accuracy(y_hat,y)
test_acc = evaluate_accuracy(test_iter,net)
print('epoch %d, loss %.4f, train acc %.3f, test acc %.3f'
% (epoch + 1, train_l_sum / len(train_iter),
train_acc_sum / len(train_iter), test_acc))
train_ch3(net, train_iter, test_iter, cross_entropy, num_epochs,
batch_size, [w, b], lr)
简单小计:
1)keepdims = True:
2)nd.pick():
3) (yhat.argmax(axis = 1) == y.astype('float32')).mean().asscalar():
取yhat中每行概率最大的类别和真实值y的类别比较后的概率(比较后得到的矩阵里面只有0和1两类),.mean()相当于求取了和真实值比较多概率。
eg:
Softmax()的Gluon实现:
%matplotlib inline
import gluonbook as gb
from mxnet import gluon, init
from mxnet.gluon import loss as gloss, nn
#读取数据
batch_size = 256
train_iter, test_iter = gb.load_data_fashion_mnist(batch_size)
#初始化模型
net = nn.Sequential()
net.add(nn.Dense(10)) #定义输出层目标为10
net.initialize(init.Normal(sigma=0.01))
#定义Softmax函数和损失
loss = gloss.SoftmaxCrossEntropyLoss()
#定义优化算法
trainer = gluon.Trainer(net.collect_params(), 'sgd', {'learning_rate': 0.1})
#训练模型
num_epochs = 5
gb.train_ch3(net, train_iter, test_iter, loss, num_epochs, batch_size, None,
None, trainer)
小计:
1)nn模块:
“nn”是 neural networks(神经网络)的缩写。顾名思义,该模块定义了大量神经网络的层。我们先定义一个模型变量net
,它是一个 Sequential 实例。在 Gluon 中,Sequential 实例可以看作是一个串联各个层的容器。在构造模型时,我们在该容器中依次添加层。当给定输入数据时,容器中的每一层将依次计算并将输出作为下一层的输入。
作为一个单层神经网络,线性回归输出层中的神经元和输入层中各个输入完全连接。因此,线性回归的输出层又叫全连接层。在 Gluon 中,全连接层是一个Dense
实例。net.add(nn.Dense(10)),表明输出层个数是10。