hi,欢迎访问本站!
当前位置: 首页学习笔记正文

【动手学——softmax】day02_Fashion-MNIST数据集&softmax两种方法实现

用户投稿 学习笔记 20阅读
softmax回归 一、获取Fashion-MNIST训练集和读取数据

我这里我们会使用torchvision包,它是服务于PyTorch深度学习框架的,主要用来构建计算机视觉模型。 -torchvision主要由以下几部分构成: torchvision.datasets: 一些加载数据的函数及常用的数据集接口; torchvision.models: 包含常用的模型结构(含预训练模型),例如AlexNet、VGG、ResNet等; torchvision.transforms: 常用的图片变换,例如裁剪、旋转等; torchvision.utils: 其他的一些有用的方法。

1.import package # import needed package%matplotlib inlinefrom IPython import displayimport matplotlib.pyplot as pltimport torchimport torchvisionimport torchvision.transforms as transformsimport timeimport syssys.path.append("/home/kesci/input")import d2lzh1981 as d2lprint(torch.__version__)print(torchvision.__version__) 2. get dataset mnist_train = torchvision.datasets.FashionMNIST(root='/home/kesci/input/FashionMNIST2065', train=True, download=True, transform=transforms.ToTensor())mnist_test = torchvision.datasets.FashionMNIST(root='/home/kesci/input/FashionMNIST2065', train=False, download=True, transform=transforms.ToTensor())

class torchvision.datasets.FashionMNIST(root, train=True, transform=None, target_transform=None, download=False)

root(string)– 数据集的根目录,其中存放processed/training.pt和processed/test.pt文件。 train(bool, 可选)– 如果设置为True,从training.pt创建数据集,否则从test.pt创建。 download(bool, 可选)– 如果设置为True,从互联网下载数据并放到root文件夹下。如果root目录下已经存在数据,不会再次下载。 transform(可被调用 , 可选)– 一种函数或变换,输入PIL图片,返回变换之后的数据。如:transforms.RandomCrop。 target_transform(可被调用 , 可选)– 一种函数或变换,输入目标,进行变换。

# show result print(type(mnist_train))print(len(mnist_train), len(mnist_test))

<class ‘torchvision.datasets.mnist.FashionMNIST’> 60000 10000

# 我们可以通过下标来访问任意一个样本feature, label = mnist_train[0]print(feature.shape, label) # Channel x Height x Width

如果不做变换输入的数据是图像,我们可以看一下图片的类型参数:

mnist_PIL = torchvision.datasets.FashionMNIST(root='/home/kesci/input/FashionMNIST2065', train=True, download=True)PIL_feature, label = mnist_PIL[0]print(PIL_feature)

<PIL.Image.Image image mode=L size=28x28 at 0x7F57E8736F28>

# 本函数已保存在d2lzh包中方便以后使用#作用:将标签转化为文本的形式#返回的是标签所对应的文本信息(文本信息是存储在text_lables这个列表中的)def get_fashion_mnist_labels(labels): text_labels = ['t-shirt', 'trouser', 'pullover', 'dress', 'coat', 'sandal', 'shirt', 'sneaker', 'bag', 'ankle boot'] return [text_labels[int(i)] for i in labels] #做一个数据集的展示def show_fashion_mnist(images, labels): d2l.use_svg_display() # 这里的_表示我们忽略(不使用)的变量 _, figs = plt.subplots(1, len(images), figsize=(12, 12)) for f, img, lbl in zip(figs, images, labels): f.imshow(img.view((28, 28)).numpy()) f.set_title(lbl) f.axes.get_xaxis().set_visible(False) f.axes.get_yaxis().set_visible(False) plt.show() X, y = [], []for i in range(10): X.append(mnist_train[i][0]) # 将第i个feature加到X中 y.append(mnist_train[i][1]) # 将第i个label加到y中show_fashion_mnist(X, get_fashion_mnist_labels(y)) # 读取数据batch_size = 256#批量大小num_workers = 4#工作线程train_iter = torch.utils.data.DataLoader(mnist_train, batch_size=batch_size, shuffle=True, num_workers=num_workers)test_iter = torch.utils.data.DataLoader(mnist_test, batch_size=batch_size, shuffle=False, num_workers=num_workers)

看看取数据花了多少时间

start = time.time()for X, y in train_iter: continueprint('%.2f sec' % (time.time() - start)) 二、softmax从零实现 import packages import torchimport torchvisionimport numpy as npimport syssys.path.append("/home/kesci/input")import d2lzh1981 as d2lprint(torch.__version__)print(torchvision.__version__) 获取训练数据集和测试数据集 batch_size = 256train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)#是对dataloader的一个封装 模型参数初始化 num_inputs = 784#输入特征是784,即X有28*28个元素print(28*28)num_outputs = 10#输出是十种类型#接下来定义权重和偏差W = torch.tensor(np.random.normal(0, 0.01, (num_inputs, num_outputs)), dtype=torch.float)b = torch.zeros(num_outputs, dtype=torch.float) #为了方便后续的反向传播,这里赋予两个参数梯度W.requires_grad_(requires_grad=True)b.requires_grad_(requires_grad=True) 对多维Tensor按维度操作 X = torch.tensor([[1, 2, 3], [4, 5, 6]])print(X.sum(dim=0, keepdim=True)) # dim为0,按照相同的列求和,并在结果中保留列特征print(X.sum(dim=1, keepdim=True)) # dim为1,按照相同的行求和,并在结果中保留行特征print(X.sum(dim=0, keepdim=False)) # dim为0,按照相同的列求和,不在结果中保留列特征print(X.sum(dim=1, keepdim=False)) # dim为1,按照相同的行求和,不在结果中保留行特征

dim = 1时,按行求和

定义softmax操作

def softmax(X): X_exp = X.exp()#指数操作,作分子 partition = X_exp.sum(dim=1, keepdim=True) #指数操作后求和,作分母 # print("X size is ", X_exp.size()) # print("partition size is ", partition, partition.size()) return X_exp / partition # 这里应用了广播机制

注释掉的两句显示X和partition的形状区别,利用了广播机制。 结果如下图

X = torch.rand((2, 5))X_prob = softmax(X)print(X_prob, '\n', X_prob.sum(dim=1)) softmax回归模型

※下面的参数x是输入特征,所以是一个行向量,通过view()函数将其变形成列向量,方便与权重w相乘,再与b相加,传入softmax函数中,得到输出y_hat

def net(X): return softmax(torch.mm(X.view((-1, num_inputs)), W) + b) 定义损失函数

y_hat = torch.tensor([[0.1, 0.3, 0.6], [0.3, 0.2, 0.5]])y = torch.LongTensor([0, 2])y_hat.gather(1, y.view(-1, 1)) def cross_entropy(y_hat, y): return - torch.log(y_hat.gather(1, y.view(-1, 1))) 定义准确率

我们模型训练完了进行模型预测的时候,会用到我们这里定义的准确率。

def accuracy(y_hat, y): return (y_hat.argmax(dim=1) == y).float().mean().item() #"y_hat.argmax(dim=1)"按行取y_hat中的最大值与真实标签y的值作比较,如果相同的话为1,不同为0;再相加起来求平均值print(accuracy(y_hat, y)) # 本函数已保存在d2lzh_pytorch包中方便以后使用。该函数将被逐步改进:它的完整实现将在“图像增广”一节中描述def evaluate_accuracy(data_iter, net): acc_sum, n = 0.0, 0 for X, y in data_iter: acc_sum += (net(X).argmax(dim=1) == y).float().sum().item() n += y.shape[0] return acc_sum / nprint(evaluate_accuracy(test_iter, net)) 训练模型 num_epochs, lr = 5, 0.1# 本函数已保存在d2lzh_pytorch包中方便以后使用def train_ch3(net, train_iter, test_iter, loss, num_epochs, batch_size, params=None, lr=None, optimizer=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: y_hat = net(X) l = loss(y_hat, y).sum() # 梯度清零 if optimizer is not None: optimizer.zero_grad() elif params is not None and params[0].grad is not None: for param in params: param.grad.data.zero_() l.backward() if optimizer is None: d2l.sgd(params, lr, batch_size) else: optimizer.step() train_l_sum += l.item() train_acc_sum += (y_hat.argmax(dim=1) == y).sum().item() n += y.shape[0] 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) 模型预测

现在我们的模型训练完了,可以进行一下预测,我们的这个模型训练的到底准确不准确。 现在就可以演示如何对图像进行分类了。给定一系列图像(第三行图像输出),我们比较一下它们的真实标签(第一行文本输出)和模型预测结果(第二行文本输出)。

X, y = iter(test_iter).next()true_labels = d2l.get_fashion_mnist_labels(y.numpy())pred_labels = d2l.get_fashion_mnist_labels(net(X).argmax(dim=1).numpy())titles = [true + '\n' + pred for true, pred in zip(true_labels, pred_labels)]d2l.show_fashion_mnist(X[0:9], titles[0:9]) softmax的简洁实现 # 加载各种包或者模块import torchfrom torch import nnfrom torch.nn import initimport numpy as npimport syssys.path.append("/home/kesci/input")import d2lzh1981 as d2lprint(torch.__version__) 初始化参数和获取数据 batch_size = 256train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size) 定义网络模型 num_inputs = 784num_outputs = 10class LinearNet(nn.Module): def __init__(self, num_inputs, num_outputs): super(LinearNet, self).__init__() #初始化28*28输入,10个输出的线性网络 self.linear = nn.Linear(num_inputs, num_outputs) def forward(self, x): # x 的形状: (batch, 1, 28, 28) #给y一个输出的"格式" y = self.linear(x.view(x.shape[0], -1)) return y # net = LinearNet(num_inputs, num_outputs)class FlattenLayer(nn.Module): def __init__(self): super(FlattenLayer, self).__init__() def forward(self, x): # x 的形状: (batch, *, *, ...) #将28*28的输出转换成784的形式 return x.view(x.shape[0], -1)#用nn.Sequential()来初始化网络from collections import OrderedDictnet = nn.Sequential( # FlattenLayer(), # LinearNet(num_inputs, num_outputs) OrderedDict([ ('flatten', FlattenLayer()), #变换层 ('linear', nn.Linear(num_inputs, num_outputs))]) #线性层,即softmax层# 或者写成我们自己定义的 LinearNet(num_inputs, num_outputs) 也可以 ) 初始化模型参数

用torch的init模块进行权重w,偏差b的初始化

init.normal_(net.linear.weight, mean=0, std=0.01)init.constant_(net.linear.bias, val=0)Parameter containing:tensor([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], requires_grad=True) 定义损失函数

交叉熵损失函数原型

loss = nn.CrossEntropyLoss() # 下面是他的函数原型# class torch.nn.CrossEntropyLoss(weight=None, size_average=None, ignore_index=-100, reduce=None, reduction='mean') 定义优化函数

一样的随机梯度下降函数,传入的是该网络的参数和超参学习率

optimizer = torch.optim.SGD(net.parameters(), lr=0.1) # 下面是函数原型# class torch.optim.SGD(params, lr=, momentum=0, dampening=0, weight_decay=0, nesterov=False) 训练 num_epochs = 5d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, batch_size, None, None, optimizer) 代码注解 X = torch.tensor([[1, 2, 3], [4, 5, 6]])print(X.sum(dim=0, keepdim=True)) # dim为0,按照相同的列求和,并在结果中保留列特征print(X.sum(dim=1, keepdim=True)) # dim为1,按照相同的行求和,并在结果中保留行特征print(X.sum(dim=0, keepdim=False)) # dim为0,按照相同的列求和,不在结果中保留列特征print(X.sum(dim=1, keepdim=False)) # dim为1,按照相同的行求和,不在结果中保留行特征

输出:

tensor([[5, 7, 9]]) tensor([[ 6], [15]]) tensor([5, 7, 9]) tensor([ 6, 15])

错题:Softmax与分类模型 答:softmax化简过程中,会减去最大项,避免因运算过大导致上溢出或下溢出,解决办法可参考笔记https://www.cnblogs.com/guohaoblog/p/12306118.html

拓展:试着比较SVM和softmax的区别和联系。

标签:
声明:无特别说明,转载请标明本文来源!
发布评论
正文 取消