From 21a115891de6bdd4b0f457684fefdeedbb1d90e9 Mon Sep 17 00:00:00 2001 From: Robin <244659184@qq.com> Date: Mon, 15 Jun 2020 17:21:19 +0800 Subject: [PATCH] Created using Colaboratory --- Untitled2.ipynb | 236 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 236 insertions(+) create mode 100644 Untitled2.ipynb diff --git a/Untitled2.ipynb b/Untitled2.ipynb new file mode 100644 index 0000000..8b5a4aa --- /dev/null +++ b/Untitled2.ipynb @@ -0,0 +1,236 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "name": "Untitled2.ipynb", + "provenance": [], + "authorship_tag": "ABX9TyP7xT9QeUCRq7zHCJ00Sn7v", + "include_colab_link": true + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "jx7orjHDqX1R", + "colab_type": "code", + "colab": {} + }, + "source": [ + "import torch\n", + "import torch.nn as nn\n", + "import torchvision\n", + "import torchvision.transforms as transforms # transforms.ToTensor()把一个取值范围是[0,255]的PIL.Image 转换成 Tensor" + ], + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "53BKy9HDqrNH", + "colab_type": "code", + "colab": {} + }, + "source": [ + "device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')" + ], + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "EFb074Gdqz6s", + "colab_type": "code", + "colab": {} + }, + "source": [ + "sequence_length = 28 # 序列长度,即一句话有多少个单词。在这里因为输入的是28*28的图像,所以理解为序列有28个单词,每个单词有28维\n", + "input_size = 28 # 输入层节点数,对应输入维度\n", + "hidden_size = 128 # 隐藏层节点数\n", + "num_layers = 2 # 2层LSTM\n", + "num_classes = 10\n", + "batch_size = 100\n", + "num_epochs = 2\n", + "learning_rate = 0.003" + ], + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "xJZZFGrNrGb8", + "colab_type": "code", + "colab": {} + }, + "source": [ + "# MNIST dataset\n", + "train_dataset = torchvision.datasets.MNIST(root='../../data/',train=True,transform=transforms.ToTensor(),download=True) \n", + "# train=True代表这个数据集作为训练集,download=True是要下载下来\n", + "\n", + "test_dataset = torchvision.datasets.MNIST(root='../../data/',train=False,transform=transforms.ToTensor()) \n", + "# train=False代表这个数据集作为测试集\n", + "\n", + "# Data loader\n", + "train_loader = torch.utils.data.DataLoader(dataset=train_dataset,batch_size=batch_size, shuffle=True) \n", + "# 上面的Dataset只负责数据的抽象,一次调用getitem只返回一个样本。\n", + "# 前面提到过,在训练神经网络时,最好是对一个batch的数据进行操作,同时还需要对数据进行shuffle和并行加速等。对此,PyTorch提供了DataLoader帮助我们实现这些功能。\n", + "\n", + "test_loader = torch.utils.data.DataLoader(dataset=test_dataset,batch_size=batch_size, shuffle=False)" + ], + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "Vad3u-masVhI", + "colab_type": "code", + "colab": {} + }, + "source": [ + "class BiRNN(nn.Module):\n", + " def __init__(self, input_size, hidden_size, num_layers, num_classes):\n", + " super(BiRNN, self).__init__() \n", + " # 使得BiRNN的实例对象可以调用父类__init__()中的属性,即执行了父类的__init__()方法,并将其中的属性附给当前子类的实例对象\n", + " self.hidden_size = hidden_size\n", + " self.num_layers = num_layers\n", + " self.lstm = nn.LSTM(input_size, hidden_size, num_layers, batch_first=True, bidirectional=True) \n", + " # batch_first的意思是在传入数据时,batch_size作为第一维。bidirectional表示是否为双向LSTM\n", + " self.fc = nn.Linear(hidden_size*2, num_classes) \n", + " # hidden_size*2是因为双向lstm的隐藏层输出是隐藏层节点数的2倍\n", + " def forward(self, x):\n", + " h0 = torch.zeros(self.num_layers*2, x.size(0), self.hidden_size).to(device) \n", + " # h_0是格式为(num_layers * num_directions, batch, hidden_size)的tensor 它包含batch中每个元素的最初的隐态,若为双向lstm num_directions=2 否则=1\n", + " c0 = torch.zeros(self.num_layers*2, x.size(0), self.hidden_size).to(device) \n", + " # c_0是格式为(seq_len, batch, input_size)的tensor 它包含batch中每个元素最初的cell state,若h_0和c_0不提供,则默认为0\n", + "\n", + " out, _ = self.lstm(x, (h0, c0)) # lstm的输入格式 \n", + " # out是形状为(seq_len, batch, num_directions*hidden_size)的tensor,包含输出特征h_t(源于LSTM每个t的最后一层)\n", + " # h_n是形状为(num_layers * num_directions, batch, hidden_size)的tensor, 包含t=seq_len(即序列末尾)的隐态值\n", + " # c_n是形状为(num_layers * num_directions, batch, hidden_size)的tensor, 包含t=seq_len(即序列末尾)的cell值\n", + " out = self.fc(out[:, -1, :]) \n", + " # 去掉out的中间维,即seq_len(因为batch_first=True,所以中间为seq_len。因为序列长度在全连接层用不到,所以去掉)。由size(100, 28, 256)变为size(100, 256)\n", + " return out" + ], + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "rl0zFWSZs52m", + "colab_type": "code", + "colab": {} + }, + "source": [ + "model = BiRNN(input_size, hidden_size, num_layers, num_classes).to(device) # to(device)是指定将model放到cpu上或者gpu上计算" + ], + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "SKcU6ly5uuAK", + "colab_type": "code", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 89 + }, + "outputId": "22476563-ab71-4c8b-f92b-cb97d8092b5b" + }, + "source": [ + "criterion = nn.CrossEntropyLoss() # 交叉熵损失\n", + "optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)\n", + "\n", + "total_step = len(train_loader) # 有多少个batch\n", + "for epoch in range(num_epochs):\n", + " for i, (images, labels) in enumerate(train_loader):\n", + " images = images.reshape(-1, sequence_length, input_size).to(device) \n", + " # 因为从train_loader中得到的images的size为(100, 1, 28, 28),所以要把1去掉\n", + " labels = labels.to(device)\n", + " outputs = model(images) \n", + " # model(images)相当于model.__call__(images),而在__call__中,调用了forward的方法。所以model(images)就相当于进行了前向传播。\n", + " loss = criterion(outputs, labels) \n", + " # outputs的维度是torch.Size([100, 10])labels的维度是torch.Size([100])。因为CrossEntropyLoss()方法进行了综合处理,所以直接这么输入就可以得到loss,可视为无缝连接。\n", + " optimizer.zero_grad() # 每次反向传播都需要将梯度归零,否则会累加,因为是一个批次一个批次进行梯度下降的,应该互不影响。\n", + " loss.backward() # 反向传播,backward函数自动实现的\n", + " optimizer.step() # 梯度更新\n", + "\n", + " if (i+1) % 100 == 0:\n", + " print('Epoch [{}/{}], Step [{}/{}], Loss: {:.4f}'.format(epoch+1, num_epochs, i+1, total_step, loss.item())) #.item()意思是将tensor值转化为python值\n" + ], + "execution_count": 58, + "outputs": [ + { + "output_type": "stream", + "text": [ + "torch.Size([100, 256])\n", + "torch.Size([100, 10]) torch.Size([100])\n", + "torch.Size([100, 256])\n", + "torch.Size([100, 10]) torch.Size([100])\n" + ], + "name": "stdout" + } + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "oXFWUqLWyPB3", + "colab_type": "code", + "colab": {} + }, + "source": [ + "with torch.no_grad():\n", + " correct = 0\n", + " total = 0\n", + " for images, labels in test_loader:\n", + " images = images.reshape(-1, sequence_length, input_size).to(device)\n", + "\n", + " labels = labels.to(device)\n", + " outputs = model(images)\n", + " print(outputs.size())\n", + " break\n", + " _, predicted = torch.max(outputs.data, 1) # outputs.data的维度是(100,10),torch.max(a, b)的意思是按照a的第b维求最大值。得到的结果是输出的labels中的最大概率以及对应的label\n", + "\n", + " total += labels.size(0)\n", + " correct += (predicted == labels).sum().item()\n", + " print('Test Accuracy of the model on the 10000 test images: {}'.format(100 * correct / total))" + ], + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "vzntDZizy2bD", + "colab_type": "code", + "colab": {} + }, + "source": [ + "" + ], + "execution_count": 0, + "outputs": [] + } + ] +} \ No newline at end of file