{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 前言\n",
    "\n",
    "原文翻译自：[Deep Learning with PyTorch: A 60 Minute Blitz](https://pytorch.org/tutorials/beginner/deep_learning_60min_blitz.html)\n",
    "\n",
    "翻译：[林不清](https://www.zhihu.com/people/lu-guo-92-42-88)\n",
    "\n",
    "整理：机器学习初学者公众号 ![gongzhong](images/gongzhong.jpg)\n",
    "\n",
    "## 目录\n",
    "\n",
    "[60分钟入门PyTorch（一）——Tensors](https://zhuanlan.zhihu.com/p/347676809)\n",
    "\n",
    "[60分钟入门PyTorch（二）——Autograd自动求导](https://zhuanlan.zhihu.com/p/347672836)\n",
    "\n",
    "[60分钟入门Pytorch（三）——神经网络](https://zhuanlan.zhihu.com/p/347678492)\n",
    "\n",
    "[60分钟入门PyTorch（四）——训练一个分类器](https://zhuanlan.zhihu.com/p/347681137)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Tensors\n",
    "\n",
    "Tensors张量是一种特殊的数据结构，它和数组还有矩阵十分相似。在Pytorch中，我们使用tensors来给模型的输入输出以及参数进行编码。\n",
    "Tensors除了张量可以在gpu或其他专用硬件上运行来加速计算之外，其他用法类似于Numpy中的ndarrays。如果你熟悉ndarrays，您就会熟悉tensor的API。如果没有，请按照这个教程，快速了解一遍API。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "import numpy as np"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 初始化Tensor\n",
    "创建Tensor有多种方法，如：\n",
    "#### 直接从数据创建\n",
    "可以直接利用数据创建tensor,数据类型会被自动推断出\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "data = [[1, 2],[3, 4]]\n",
    "x_data = torch.tensor(data)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 从Numpy创建\n",
    "Tensor 可以直接从numpy的array创建（反之亦然-参见`bridge-to-np-label`）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "np_array = np.array(data)\n",
    "x_np = torch.from_numpy(np_array)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 从其他tensor创建\n",
    "新的tensor保留了参数tensor的一些属性（形状，数据类型），除非显式覆盖"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Ones Tensor: \n",
      " tensor([[1, 1],\n",
      "        [1, 1]]) \n",
      "\n",
      "Random Tensor: \n",
      " tensor([[0.6075, 0.4581],\n",
      "        [0.5631, 0.1357]]) \n",
      "\n"
     ]
    }
   ],
   "source": [
    "x_ones = torch.ones_like(x_data) # retains the properties of x_data\n",
    "print(f\"Ones Tensor: \\n {x_ones} \\n\")\n",
    "\n",
    "x_rand = torch.rand_like(x_data, dtype=torch.float) # overrides the datatype of x_data\n",
    "print(f\"Random Tensor: \\n {x_rand} \\n\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 从常数或者随机数创建\n",
    "``shape``是关于tensor维度的一个元组，在下面的函数中，它决定了输出tensor的维数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Random Tensor: \n",
      " tensor([[0.7488, 0.0891, 0.8417],\n",
      "        [0.0783, 0.5984, 0.5709]]) \n",
      "\n",
      "Ones Tensor: \n",
      " tensor([[1., 1., 1.],\n",
      "        [1., 1., 1.]]) \n",
      "\n",
      "Zeros Tensor: \n",
      " tensor([[0., 0., 0.],\n",
      "        [0., 0., 0.]])\n"
     ]
    }
   ],
   "source": [
    "shape = (2,3,)\n",
    "rand_tensor = torch.rand(shape)\n",
    "ones_tensor = torch.ones(shape)\n",
    "zeros_tensor = torch.zeros(shape)\n",
    "\n",
    "print(f\"Random Tensor: \\n {rand_tensor} \\n\")\n",
    "print(f\"Ones Tensor: \\n {ones_tensor} \\n\")\n",
    "print(f\"Zeros Tensor: \\n {zeros_tensor}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Tensor的属性\n",
    "Tensor的属性包括形状，数据类型以及存储的设备"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Shape of tensor: torch.Size([3, 4])\n",
      "Datatype of tensor: torch.float32\n",
      "Device tensor is stored on: cpu\n"
     ]
    }
   ],
   "source": [
    "tensor = torch.rand(3,4)\n",
    "\n",
    "print(f\"Shape of tensor: {tensor.shape}\")\n",
    "print(f\"Datatype of tensor: {tensor.dtype}\")\n",
    "print(f\"Device tensor is stored on: {tensor.device}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Tensor的操作\n",
    "Tensor有超过100个操作，包括 transposing, indexing, slicing, mathematical operations, linear algebra, random sampling,更多详细的介绍请点击[这里](https://pytorch.org/docs/stable/torch.html)\n",
    "\n",
    "它们都可以在GPU上运行（速度通常比CPU快），如果你使用的是Colab，通过编辑>笔记本设置来分配一个GPU。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "# We move our tensor to the GPU if available\n",
    "if torch.cuda.is_available():\n",
    "  tensor = tensor.to('cuda')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "尝试列表中的一些操作。如果你熟悉NumPy API，你会发现tensor的API很容易使用。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 标准的numpy类索引和切片:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([[1., 0., 1., 1.],\n",
      "        [1., 0., 1., 1.],\n",
      "        [1., 0., 1., 1.],\n",
      "        [1., 0., 1., 1.]])\n"
     ]
    }
   ],
   "source": [
    "tensor = torch.ones(4, 4)\n",
    "tensor[:,1] = 0\n",
    "print(tensor)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 合并tensors \n",
    "可以使用``torch.cat``来沿着特定维数连接一系列张量。 [``torch.stack``](https://pytorch.org/docs/stable/generated/torch.stack.html)另一个加入op的张量与``torch.cat``有细微的不同"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([[1., 0., 1., 1., 1., 0., 1., 1., 1., 0., 1., 1.],\n",
      "        [1., 0., 1., 1., 1., 0., 1., 1., 1., 0., 1., 1.],\n",
      "        [1., 0., 1., 1., 1., 0., 1., 1., 1., 0., 1., 1.],\n",
      "        [1., 0., 1., 1., 1., 0., 1., 1., 1., 0., 1., 1.]])\n"
     ]
    }
   ],
   "source": [
    "t1 = torch.cat([tensor, tensor, tensor], dim=1)\n",
    "print(t1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 增加tensors"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor.mul(tensor) \n",
      " tensor([[1., 0., 1., 1.],\n",
      "        [1., 0., 1., 1.],\n",
      "        [1., 0., 1., 1.],\n",
      "        [1., 0., 1., 1.]]) \n",
      "\n",
      "tensor * tensor \n",
      " tensor([[1., 0., 1., 1.],\n",
      "        [1., 0., 1., 1.],\n",
      "        [1., 0., 1., 1.],\n",
      "        [1., 0., 1., 1.]])\n"
     ]
    }
   ],
   "source": [
    "# This computes the element-wise product\n",
    "print(f\"tensor.mul(tensor) \\n {tensor.mul(tensor)} \\n\")\n",
    "# Alternative syntax:\n",
    "print(f\"tensor * tensor \\n {tensor * tensor}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "它计算两个tensor之间的矩阵乘法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor.matmul(tensor.T) \n",
      " tensor([[3., 3., 3., 3.],\n",
      "        [3., 3., 3., 3.],\n",
      "        [3., 3., 3., 3.],\n",
      "        [3., 3., 3., 3.]]) \n",
      "\n",
      "tensor @ tensor.T \n",
      " tensor([[3., 3., 3., 3.],\n",
      "        [3., 3., 3., 3.],\n",
      "        [3., 3., 3., 3.],\n",
      "        [3., 3., 3., 3.]])\n"
     ]
    }
   ],
   "source": [
    "print(f\"tensor.matmul(tensor.T) \\n {tensor.matmul(tensor.T)} \\n\")\n",
    "# Alternative syntax:\n",
    "print(f\"tensor @ tensor.T \\n {tensor @ tensor.T}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 原地操作\n",
    "带有后缀``_``的操作表示的是原地操作，例如： ``x.copy_(y)``, ``x.t_()``将改变 ``x``."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([[1., 0., 1., 1.],\n",
      "        [1., 0., 1., 1.],\n",
      "        [1., 0., 1., 1.],\n",
      "        [1., 0., 1., 1.]]) \n",
      "\n",
      "tensor([[6., 5., 6., 6.],\n",
      "        [6., 5., 6., 6.],\n",
      "        [6., 5., 6., 6.],\n",
      "        [6., 5., 6., 6.]])\n"
     ]
    }
   ],
   "source": [
    "print(tensor, \"\\n\")\n",
    "tensor.add_(5)\n",
    "print(tensor)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-info\"><h4>注意</h4>\n",
    "    <p>原地操作虽然会节省许多空间，但是由于会立刻清除历史记录所以在计算导数时可能会有问题，因此不建议使用</p></div>\n",
    "    \n",
    "### Tensor转换为Numpt 数组"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "t: tensor([1., 1., 1., 1., 1.])\n",
      "n: [1. 1. 1. 1. 1.]\n"
     ]
    }
   ],
   "source": [
    "t = torch.ones(5)\n",
    "print(f\"t: {t}\")\n",
    "n = t.numpy()\n",
    "print(f\"n: {n}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "tensor的变化反映在NumPy数组中。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "t: tensor([2., 2., 2., 2., 2.])\n",
      "n: [2. 2. 2. 2. 2.]\n"
     ]
    }
   ],
   "source": [
    "t.add_(1)\n",
    "print(f\"t: {t}\")\n",
    "print(f\"n: {n}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Numpy数组转换为Tensor"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "n = np.ones(5)\n",
    "t = torch.from_numpy(n)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "NumPy数组的变化反映在tensor中"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "t: tensor([2., 2., 2., 2., 2.], dtype=torch.float64)\n",
      "n: [2. 2. 2. 2. 2.]\n"
     ]
    }
   ],
   "source": [
    "np.add(n, 1, out=n)\n",
    "print(f\"t: {t}\")\n",
    "print(f\"n: {n}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
