softmax回归是Logistic回归在多分类问题上的推广,一般用于神经网络的输出层,此时输出层叫做softmax层。这里用softmax回归做一个简单的神经网络,利用该模型对衣服鞋子进行分类,数据采用d2lzh中的Fashion-MNIST数据集
这个函数可以将一个向量(x1,x2,...,xK)映射为一个概率分布(z1,z2,...,zK),它将数据的范围映射到(0,1)区间:
对今天的图片分类来说,一个图片数据根据神经网络计算可以得到1*10大小的向量(为什么是10,因为总共分成10个类型),然后将这个向量带入上述公式,就可以得到这个图片属于每个类型的可能性大小,后面会讲如何根据这个可能性的向量构造相应的损失函数。
%matplotlib inline
import d2lzh as d2l
from mxnet import autograd, nd
batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)#将数据集按batch_size大小分为256一份
#看看这些图片长什么样
for i,j in train_iter:
break
d2l.show_fashion_mnist(i[0:9], d2l.get_fashion_mnist_labels(j.asnumpy())[0:9])
解释下怎么生成这些图片,首先从train_iter训练集中提取一份数据,通过for循环加break跳出操作,这一份数据里面有256张图片,此时i,j里面分别是训练集中的一部分输入和输出,i[0:9]表示取10张图片数据,d2l.get_fashion_mnist_labels(j.asnumpy())的作用是将j转化为数组后(原先j是张量,里面是范围在0-9的整数,标签为10种类型),然后将数组中的数字转化为对应的物品名称,show_fashion_mnist(放入数据集张量,放入名称列表)。
好,训练集测试集都有了,正式开始
num_inputs = 784
num_outputs = 10
W = nd.random.normal(scale=0.01, shape=(num_inputs, num_outputs))
b = nd.zeros(num_outputs)
W.attach_grad()
b.attach_grad()
因为图片是28*28像素的,后面会通过reshape转为1*784的,固这里w的shape设为784*10,随机生成服从(0,0.01)正态分布的数据,然后W.attach_grad(),b.attach_grad()给参数申请内存求导,这样根据损失函数就可以更新参数了,必加。
def softmax(X):
X_exp = X.exp()
partition = X_exp.sum(axis=1, keepdims=True)
return X_exp / partition # 这里应用了广播机制
def net(X):
return softmax(nd.dot(X.reshape((-1, num_inputs)), W) + b)
def cross_entropy(y_hat, y):
return -nd.pick(y_hat, y).log()
def evaluate_accuracy(data_iter, net):
acc_sum, n = 0.0, 0
for X, y in data_iter:
y = y.astype('float32')
acc_sum += (net(X).argmax(axis=1) == y).sum().asscalar()
n += y.size
return acc_sum / n
定义好softmax函数和net函数,softmax函数公式上文已讲,然后net函数是根据w,b计算出1*10的向量然后根据softmax函数转化为对应的概率大小,这里通过reshape来将28*28的像素矩阵转化为1*784向量,cross_entropy计算损失函数,其实就是根据图片实际对应的类型,然后找到类型对应的模型计算出来的概率大小,对这个概率log下然后加负数,evaluate_accuracy计算模型的准确率
num_epochs, lr = 5, 0.1
# 本函数已保存在d2lzh包中方便以后使用
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, train_acc_sum, n = 0.0, 0.0, 0
for X, y in train_iter:
with autograd.record():
y_hat = net(X)
l = loss(y_hat, y).sum()
l.backward()
if trainer is None:
d2l.sgd(params, lr, batch_size)
else:
trainer.step(batch_size) # “softmax回归的简洁实现”一节将用到
y = y.astype('float32')
train_l_sum += l.asscalar()
train_acc_sum += (y_hat.argmax(axis=1) == y).sum().asscalar()
n += y.size
test_acc = evaluate_accuracy(test_iter, net)
print('epoch %d, loss %.4f, train acc %.3f, test acc %.3f'
% (epoch + 1, train_l_sum / n, train_acc_sum / n, test_acc))
train_ch3(net, train_iter, test_iter, cross_entropy, num_epochs, batch_size,
[W, b], lr)
这里设置num_epochs,lr 分别等于5,0.1代表总共迭代五次,学习速率为0.1
依次train_ch3函数中分别放入net模型计算方式,训练集和测试集,cross_entropy损失函数,循环次数,小批量样本数,权重偏差,学习速率
结果如下:
看着迭代五次后结果好像没什么变化,是因为我做过好几次了,权重一直在更新,所以准确率什么的都增加不大
for X, y in test_iter:
break
true_labels = d2l.get_fashion_mnist_labels(y.asnumpy())
pred_labels = d2l.get_fashion_mnist_labels(net(X).argmax(axis=1).asnumpy())
titles = [true + '\n' + pred for true, pred in zip(true_labels, pred_labels)]
d2l.show_fashion_mnist(X[0:9], titles[0:9])
看看图片效果
可以看到4,5,6件分类错误,其他正确,效果还不错70%的准确率
以上就是softmax回归的一个代码实现,有任何问题,欢迎讨论