pytorch基础

文章目录

下载安装:

https://pytorch.org/get-started/locally/

张量tensor

简介

几何代数中定义的张量是基于向量和矩阵的推广,比如我们可以将标量视为零阶张量,矢量可以视为一阶张量,矩阵就是二阶张量。

0维张量/标量 标量是一个数字(scalar)

x = torch.tensor(42.)
x
'''
tensor(42.)
'''
x.dim()#维度
'''
0
'''
x.item()#返回value
'''
42.0
'''
2 * x
'''
tensor(84.)
'''

1维张量/向量 1维张量称为“向量”。(vector)

v = torch.tensor([1.5, -0.5, 3.0])
v
'''
tensor([ 1.5000, -0.5000,  3.0000])
'''
v.dim()
'''
1
'''
v.size()
'''
torch.Size([3])
'''

2维张量 2维张量称为矩阵(matrix)

M = torch.tensor([[1., 2.], [3., 4.]])
M
'''
tensor([[1., 2.],
        [3., 4.]])
'''
M.mean()#求均值
'''
tensor(2.5000)
'''

乘法

M.matmul(M)
'''
tensor([[ 7., 10.],
        [15., 22.]])
'''
torch.tensor([1., 0.]).matmul(M)
'''
tensor([1., 2.])
'''
M * M
'''
tensor([[ 1.,  4.],
        [ 9., 16.]])
'''
torch.tensor([1., 2.]).matmul(M)
'''
tensor([ 7., 10.])
'''

加法

x = torch.rand(4, 3) 
x
'''
tensor([[0.3352, 0.2696, 0.5885],
        [0.3994, 0.0066, 0.2920],
        [0.1103, 0.7191, 0.3511],
        [0.5951, 0.7503, 0.8069]])
'''
y = torch.rand(4, 3) 
y
'''
tensor([[0.9592, 0.7950, 0.2895],
        [0.7109, 0.9559, 0.0147],
        [0.7786, 0.7916, 0.2050],
        [0.2201, 0.9062, 0.3068]])
'''
x + y
'''
tensor([[1.2944, 1.0646, 0.8780],
        [1.1103, 0.9625, 0.3067],
        [0.8889, 1.5107, 0.5561],
        [0.8152, 1.6564, 1.1137]])
'''
torch.add(x, y)
'''
tensor([[1.2944, 1.0646, 0.8780],
        [1.1103, 0.9625, 0.3067],
        [0.8889, 1.5107, 0.5561],
        [0.8152, 1.6564, 1.1137]])
'''
# 方式3 提供一个输出 tensor 作为参数
result = torch.empty(4, 3) 
torch.add(x, y, out=result) 
print(result)
'''
tensor([[1.2944, 1.0646, 0.8780],
        [1.1103, 0.9625, 0.3067],
        [0.8889, 1.5107, 0.5561],
        [0.8152, 1.6564, 1.1137]])
'''
# 方式4 in-place
y.add_(x) 
print(y)
'''
tensor([[1.2944, 1.0646, 0.8780],
        [1.1103, 0.9625, 0.3067],
        [0.8889, 1.5107, 0.5561],
        [0.8152, 1.6564, 1.1137]])
'''

3维张量 :公用数据存储在张量 时间序列数据 股价 文本数据 彩色图片(RGB) (n-dimensional tensor)

使用PIL读入一张图片

from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
​
pil_im = Image.open('01.jpg')
​
plt.imshow(pil_im)
plt.show()

对于计算机来说,图像是一个由数字组成的巨大的三维数组。在这个图的例子中,图像的大小是高198像素,宽190像素,有3个颜色通道,分别是红、绿和蓝(简称RGB)。如此,该图像就包含了198×190×3=112860个数字,每个数字都是处于范围0~255之间的整型,其中0表示黑,255表示白。

np_im = np.array(pil_im)
print(np_im.shape,np_im.dtype)
np_im
'''
(198, 190, 3) uint8
array([[[ 30,  29,  35],
        [ 30,  29,  35],
        [ 36,  35,  41],
        ...,
        [ 27,  31,  30],
        [ 30,  32,  31],
        [ 40,  42,  41]],

       [[ 32,  31,  37],
        [ 28,  27,  33],
        [ 28,  27,  33],
        ...,
        [ 27,  31,  30],
        [ 30,  32,  31],
        [ 40,  42,  41]],

       [[ 31,  30,  35],
        [ 25,  24,  29],
        [ 22,  21,  26],
        ...,
        [ 27,  31,  30],
        [ 30,  32,  31],
        [ 40,  42,  41]],

       ...,

       [[173, 180, 172],
        [174, 181, 173],
        [175, 182, 174],
        ...,
        [158, 159, 153],
        [159, 160, 155],
        [160, 161, 156]],

       [[161, 168, 160],
        [164, 171, 163],
        [168, 175, 167],
        ...,
        [162, 163, 157],
        [164, 165, 160],
        [164, 165, 160]],

       [[156, 163, 155],
        [160, 167, 159],
        [165, 172, 164],
        ...,
        [165, 166, 160],
        [166, 167, 162],
        [167, 168, 163]]], dtype=uint8)
'''

转换为tensor格式

tensor_pil = torch.from_numpy(np.transpose(np_im, (2, 0, 1)))
tensor_pil
'''
tensor([[[ 30,  30,  36,  ...,  27,  30,  40],
         [ 32,  28,  28,  ...,  27,  30,  40],
         [ 31,  25,  22,  ...,  27,  30,  40],
         ...,
         [173, 174, 175,  ..., 158, 159, 160],
         [161, 164, 168,  ..., 162, 164, 164],
         [156, 160, 165,  ..., 165, 166, 167]],

        [[ 29,  29,  35,  ...,  31,  32,  42],
         [ 31,  27,  27,  ...,  31,  32,  42],
         [ 30,  24,  21,  ...,  31,  32,  42],
         ...,
         [180, 181, 182,  ..., 159, 160, 161],
         [168, 171, 175,  ..., 163, 165, 165],
         [163, 167, 172,  ..., 166, 167, 168]],

        [[ 35,  35,  41,  ...,  30,  31,  41],
         [ 37,  33,  33,  ...,  30,  31,  41],
         [ 35,  29,  26,  ...,  30,  31,  41],
         ...,
         [172, 173, 174,  ..., 153, 155, 156],
         [160, 163, 167,  ..., 157, 160, 160],
         [155, 159, 164,  ..., 160, 162, 163]]], dtype=torch.uint8)
'''
tensor_pil.dim()
'''
3
'''
tensor_pil.size()
'''
torch.Size([3, 198, 190])
'''

张量是现代机器学习的基础。它的核心是一个数据容器,多数情况下,它包含数字,有时候它也包含字符串,但这种情况比较少。因此可以把它想象成一个数字的水桶。

这里有一些存储在各种类型张量的公用数据集类型:

3维=时间序列
4维=图像
5维=视频
例子:一个图像可以用三个字段表示:

(width, height, channel) = 3D

但是,在机器学习工作中,我们经常要处理不止一张图片或一篇文档——我们要处理一个集合。我们可能有10,000张郁金香的图片,这意味着,我们将用到4D张量:

(sample_size, width, height, channel) = 4D

在PyTorch中, torch.Tensor 是存储和变换数据的主要工具。如果你之前用过NumPy,你会发现 Tensor 和NumPy的多维数组非常类似。然而,Tensor 提供GPU计算和自动求梯度等更多功能,这些使 Tensor 这一数据类型更加适合深度学习。

pytorch基础

创建tensor

import torch #导包
?torch.tensor #查看文档

常见的构造Tensor的函数

a = torch.rand(2, 3) #构造一个随机初始化的矩阵
a
'''
tensor([[0.8229, 0.3761, 0.9514],
        [0.1849, 0.7565, 0.7958]])
'''
b = torch.randn(4, 2) #随机数服从正态分布
b
'''
tensor([[ 0.3622,  0.4899],
        [-0.5874,  0.0016],
        [ 0.8994, -0.5036],
        [ 0.9156,  0.3732]])
'''
c = torch.ones(2, 3) #全1
c
'''
tensor([[1., 1., 1.],
        [1., 1., 1.]])
'''
d = torch.zeros(2, 3) #全0
d
'''
tensor([[0., 0., 0.],
        [0., 0., 0.]])
'''
e = torch.arange(0, 10, 2) #从0到10,步长为2
e
'''
tensor([0, 2, 4, 6, 8])
'''
f = torch.linspace(1,10,5) #从1到10,均分为5个
f
'''
tensor([ 1.0000,  3.2500,  5.5000,  7.7500, 10.0000])
'''
g = torch.eye(3,2) #对角为1,其余为0
g
'''
tensor([[1., 0.],
        [0., 1.],
        [0., 0.]])
'''
h = torch.randperm(10) #随机排列
h
'''
tensor([3, 0, 1, 8, 4, 5, 7, 9, 6, 2])
'''
i = torch.tensor([5.5, 3]) #直接使用数据,构造一个张量
i
'''
tensor([5.5000, 3.0000])
'''

基于已经存在的 tensor,创建一个 tensor :

j = i.new_ones(4, 3, dtype=torch.double) # 创建一个新的tensor,返回的tensor默认具有相同的 torch.dtype和torch.device
# 也可以像之前的写法 x = torch.ones(4, 3, dtype=torch.double)
print(j)
k = torch.randn_like(j, dtype=torch.float)
# 重置数据类型
print(k)
# 结果会有一样的size
'''
tensor([[1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.]], dtype=torch.float64)
tensor([[ 1.4550,  0.7617, -0.0454],
        [-0.5241, -0.1855, -0.1790],
        [ 0.1177,  0.5916,  0.1550],
        [-1.1339, -1.9725, -1.4337]])
'''

empty创建一个未被初始化数值的tensor,tensor的大小是由size确定

l=torch.empty(size=[2,4],out=k)
l
'''
tensor([[ 1.4550,  0.7617, -0.0454, -0.5241],
        [-0.1855, -0.1790,  0.1177,  0.5916]])
'''

创建tensor,用dtype指定类型。注意类型要匹配

m = torch.tensor(1.0, dtype=torch.float)
n = torch.tensor(1, dtype=torch.long)
o = torch.tensor(1.0, dtype=torch.int8)
print(m, n, o)
'''
tensor(1.) tensor(1) tensor(1, dtype=torch.int8)
'''

使用指定类型函数随机初始化指定大小的tensor

p = torch.FloatTensor(2,3)
q = torch.IntTensor(2)
r = torch.IntTensor([1,2,3,4])  #对于python已经定义好的数据结构可以直接转换
print(p, '\n', q, '\n', r)
'''
tensor([[4.1026e-08, 2.0826e+23, 1.0258e-08],
        [3.3528e-09, 2.7477e-06, 1.7186e-04]]) 
 tensor([1, 0], dtype=torch.int32) 
 tensor([1, 2, 3, 4], dtype=torch.int32)
'''

tensor和numpy array之间的相互转换

s = np.array([[1,2,3],[4,5,6]])
print(s)
t = torch.tensor(s)
print(t)
u = torch.from_numpy(s)
print(u)
v = u.numpy()
print(v)
'''
[[1 2 3]
 [4 5 6]]
tensor([[1, 2, 3],
        [4, 5, 6]], dtype=torch.int32)
tensor([[1, 2, 3],
        [4, 5, 6]], dtype=torch.int32)
[[1 2 3]
 [4 5 6]]
'''

扩展&压缩tensor的维度:squeeze

w = u.unsqueeze(1)#unsqueeze:扩充数据维度,在0起的指定位置N加上维数为一的维度
print(w)
print(w.shape,'\n')
​
x = w.squeeze(0)
print(x)
print(x.shape,'\n')
​
y = w.squeeze(1)#squeeze:维度压缩,在0起的指定位置,去掉维数为1的的维度
print(y)
print(y.shape)
'''
tensor([[[1, 2, 3]],

        [[4, 5, 6]]], dtype=torch.int32)
torch.Size([2, 1, 3]) 

tensor([[[1, 2, 3]],

        [[4, 5, 6]]], dtype=torch.int32)
torch.Size([2, 1, 3]) 

tensor([[1, 2, 3],
        [4, 5, 6]], dtype=torch.int32)
torch.Size([2, 3])
'''

索引操作:(类似于numpy)

print(u)
z = u[0,:]
z += 1
print(z)
print(u[0, :]) # 源tensor也被改了了
'''
tensor([[1, 2, 3],
        [4, 5, 6]], dtype=torch.int32)
tensor([2, 3, 4], dtype=torch.int32)
tensor([2, 3, 4], dtype=torch.int32)
'''

view操作可以改变矩阵维度

x = torch.randn(2, 4)
y = x.view(8)
z = x.view(-1, 2) # -1是指这一维的维数由其他维度决定
print(x,'\n',y,'\n',z,'\n')
print(x.size(), y.size(), z.size(),'\n')
​
#注意 view() 返回的新tensor与源tensor共享内存(其实是同一个tensor),也即更改其中的一个,另 外一个也会跟着改变。(顾名思义,view仅仅是改变了对这个张量的观察⻆度)
x += 1
print(x,'\n')
print(y) # 也加了1
'''
tensor([[-0.8137,  1.2395, -0.3258,  0.1758],
        [-0.6160, -1.8669,  0.9111,  0.1596]]) 
 tensor([-0.8137,  1.2395, -0.3258,  0.1758, -0.6160, -1.8669,  0.9111,  0.1596]) 
 tensor([[-0.8137,  1.2395],
        [-0.3258,  0.1758],
        [-0.6160, -1.8669],
        [ 0.9111,  0.1596]]) 

torch.Size([2, 4]) torch.Size([8]) torch.Size([4, 2]) 

tensor([[ 0.1863,  2.2395,  0.6742,  1.1758],
        [ 0.3840, -0.8669,  1.9111,  1.1596]]) 

tensor([ 0.1863,  2.2395,  0.6742,  1.1758,  0.3840, -0.8669,  1.9111,  1.1596])
'''

不想改变原始数据的话可以先用 clone 创造一个副本然后再使用 view

注意:使用 clone 还有一个好处是会被记录在计算图中,即梯度回传到副本时也会传到源 Tensor 。

w = x.clone()
w
'''
tensor([[ 0.1863,  2.2395,  0.6742,  1.1758],
        [ 0.3840, -0.8669,  1.9111,  1.1596]])
'''

广播机制

当对两个形状不同的 Tensor 按元素运算时,可能会触发广播(broadcasting)机制:先适当复制元素使这两个 Tensor 形状相同后再按元素运算。

x = torch.arange(1, 3).view(1, 2)
print(x)
y = torch.arange(1, 4).view(3, 1)
print(y)
print(x + y)
'''
tensor([[1, 2]])
tensor([[1],
        [2],
        [3]])
tensor([[2, 3],
        [3, 4],
        [4, 5]])
'''

自动求导autograd

PyTorch 中,所有神经网络的核心是 autograd包。autograd包为张量上的所有操作提供了自动求导机制。它是一个在运行时定义 ( define-by-run )的框架,这意味着反向传播是根据代码如何运行来决定的,并且每次迭代可以是不同的。

torch.Tensor是这个包的核心类。如果设置它的属性.requires_gradTrue,那么它将会追踪对于该张量的所有操作。当完成计算后可以通过调用.backward(),来自动计算所有的梯度。这个张量的所有梯度将会自动累加到.grad属性。

注意:在 y.backward() 时,如果 y 是标量,则不需要为 backward() 传入任何参数;否则,需要传入一个与 y 同形的Tensor。

要阻止一个张量被跟踪历史,可以调用.detach()方法将其与计算历史分离,并阻止它未来的计算记录被跟踪。为了防止跟踪历史记录(和使用内存),可以将代码块包装在 with torch.no_grad():中。在评估模型时特别有用,因为模型可能具有 requires_grad = True 的可训练的参数,但是我们不需要在此过程中对他们进行梯度计算。

还有一个类对于autograd的实现非常重要:FunctionTensorFunction 互相连接生成了一个无环图 (acyclic graph),它编码了完整的计算历史。每个张量都有一个.grad_fn属性,该属性引用了创建 Tensor自身的Function(除非这个张量是用户手动创建的,即这个张量的grad_fnNone )。

如果需要计算导数,可以在 Tensor 上调用 .backward()。如果Tensor 是一个标量(即它包含一个元素的数据),则不需要为 backward()指定任何参数,但是如果它有更多的元素,则需要指定一个gradient参数,该参数是形状匹配的张量。

现在创建一个张量并设置requires_grad = True以跟踪它的计算

x = torch.ones(2, 2, requires_grad=True)
print(x)
'''
tensor([[1., 1.],
        [1., 1.]], requires_grad=True)
'''

在张量上执行操作:

y = x + 2
print(y)
'''
tensor([[3., 3.],
        [3., 3.]], grad_fn=<AddBackward0>)
'''

因为y是通过一个操作创建的,所以它有grad_fn,而x是由用户创建,所以它的grad_fn为None.

print(y.grad_fn)
print(x.grad_fn)
'''
<AddBackward0 object at 0x0000018103A75FA0>
None
'''

在y上执行操作

z = y * y * 3
out = z.mean()
print(z,'\n', out)
'''
tensor([[27., 27.],
        [27., 27.]], grad_fn=<MulBackward0>) 
 tensor(27., grad_fn=<MeanBackward0>)
'''

梯度(Gradients)

现在我们来执行反向传播,out.backward相当于执行out.backward(torch.tensor(1.))

输出out对x的梯度d(out)/dx:

out.backward(retain_graph=True)
#进行一次backward之后,各个节点的值会清除,这样进行第二次backward会报错,如果加上retain_graph==True后,可以再来一次backward
print(x.grad)
'''
tensor([[4.5000, 4.5000],
        [4.5000, 4.5000]])
'''

z i = 3 ( x i + 2 ) 2 z_i=3(x_i+2)^2 zi​=3(xi​+2)2

o u t = z . m e a n ( ) = 1 4 ∑ z i = 3 4 ( x i + 2 ) 2 out=z.mean()=\frac{1}{4}\sum z_i=\frac{3}{4}(x_i+2)^2 out=z.mean()=41​∑zi​=43​(xi​+2)2

求导 ∂ o u t ∂ x i = 3 2 ( x i + 2 ) \frac{\partial out}{\partial x_i}=\frac{3}{2}(x_i+2) ∂xi​∂out​=23​(xi​+2)

out.backward相当于执行out.backward(torch.tensor(1.)),所以 x i = 1 x_i=1 xi​=1

∂ ( o u t ) ∂ x i = 9 2 = 4.5 \frac{\partial (out)}{\partial x_i}=\frac{9}{2}=4.5 ∂xi​∂(out)​=29​=4.5

注意:grad在反向传播过程中是累加的(accumulated),这意味着每一次运行反向传播,梯度都会累加之前的梯度,所以一般在反向传播之前需把梯度清零。

out.backward(retain_graph=True)
print(x.grad)
'''
tensor([[9., 9.],
        [9., 9.]])
'''
out.backward(retain_graph=True)
print(x.grad)
'''
tensor([[13.5000, 13.5000],
        [13.5000, 13.5000]])
'''
out2 = x.sum()
out2.backward(retain_graph=True)
print(x.grad)
'''
tensor([[14.5000, 14.5000],
        [14.5000, 14.5000]])
'''

清零

x.grad.data.zero_()
print(x.grad)
out2.backward(retain_graph=True)
print(x.grad)
'''
tensor([[0., 0.],
        [0., 0.]])
tensor([[1., 1.],
        [1., 1.]])
'''

雅可比向量积

数学上,若有向量函数 y ⃗ = f ( x ⃗ ) \vec{y}=f(\vec{x}) y ​=f(x ),那么 y ⃗ \vec{y} y ​ 关于 x ⃗ \vec{x} x 的梯度就是一个雅可比矩阵:
J = ( ∂ y 1 ∂ x 1 ⋯ ∂ y 1 ∂ x n ⋮ ⋱ ⋮ ∂ y m ∂ x 1 ⋯ ∂ y m ∂ x n ) J=\left(\begin{array}{ccc}\frac{\partial y_{1}}{\partial x_{1}} & \cdots & \frac{\partial y_{1}}{\partial x_{n}} \\ \vdots & \ddots & \vdots \\ \frac{\partial y_{m}}{\partial x_{1}} & \cdots & \frac{\partial y_{m}}{\partial x_{n}}\end{array}\right) J=⎝⎜⎛​∂x1​∂y1​​⋮∂x1​∂ym​​​⋯⋱⋯​∂xn​∂y1​​⋮∂xn​∂ym​​​⎠⎟⎞​
torch.autograd 这个包就是用来计算一些雅可比矩阵向量积的。例如,如果 v v v 是一个标量函数 l = g ( y ⃗ ) l = g(\vec{y}) l=g(y ​) 的梯度:
v = ( ∂ l ∂ y 1 ⋯ ∂ l ∂ y m ) v=\left(\begin{array}{lll}\frac{\partial l}{\partial y_{1}} & \cdots & \frac{\partial l}{\partial y_{m}}\end{array}\right) v=(∂y1​∂l​​⋯​∂ym​∂l​​)
由链式法则,雅可比向量积就是 l l l关于 x ⃗ \vec{x} x 的梯度:
v J = ( ∂ l ∂ y 1 ⋯ ∂ l ∂ y m ) ( ∂ y 1 ∂ x 1 ⋯ ∂ y 1 ∂ x n ⋮ ⋱ ⋮ ∂ y m ∂ x 1 ⋯ ∂ y m ∂ x n ) = ( ∂ l ∂ x 1 ⋯ ∂ l ∂ x n ) v J=\left(\begin{array}{lll}\frac{\partial l}{\partial y_{1}} & \cdots & \frac{\partial l}{\partial y_{m}}\end{array}\right)\left(\begin{array}{ccc}\frac{\partial y_{1}}{\partial x_{1}} & \cdots & \frac{\partial y_{1}}{\partial x_{n}} \\ \vdots & \ddots & \vdots \\ \frac{\partial y_{m}}{\partial x_{1}} & \cdots & \frac{\partial y_{m}}{\partial x_{n}}\end{array}\right)=\left(\begin{array}{lll}\frac{\partial l}{\partial x_{1}} & \cdots & \frac{\partial l}{\partial x_{n}}\end{array}\right) vJ=(∂y1​∂l​​⋯​∂ym​∂l​​)⎝⎜⎛​∂x1​∂y1​​⋮∂x1​∂ym​​​⋯⋱⋯​∂xn​∂y1​​⋮∂xn​∂ym​​​⎠⎟⎞​=(∂x1​∂l​​⋯​∂xn​∂l​​)

现在让我们来看一个雅可比向量积的例子:

x = torch.randn(3, requires_grad=True)
print(x)
​
y = x * 2
i = 0
while y.data.norm() < 1000:
    y = y * 2
    i = i + 1
print(y)
print(i)
'''
tensor([-2.0557,  0.4788, -1.5765], requires_grad=True)
tensor([-1052.4996,   245.1473,  -807.1833], grad_fn=<MulBackward0>)
8
'''

现在在这种情况下,y 不再是一个标量。torch.autograd 不能够直接计算整个雅可比,但是如果我们只想要雅可比向量积,只需要简单的传递向量给 backward 作为参数。

y.backward()
print(x.grad)
'''
RuntimeError: grad can be implicitly created only for scalar outputs
'''
v = torch.tensor([0.1, 1.0, 0.0001], dtype=torch.float)
y.backward(v)
​
print(x.grad)
'''
tensor([5.1200e+01, 5.1200e+02, 5.1200e-02])
'''

你可以通过将代码包裹在 with torch.no_grad(),来停止对从跟踪历史中 的 .requires_grad=True 的张量自动求导。

print(x.requires_grad)
print((x ** 2).requires_grad)
​
with torch.no_grad():
    print((x ** 2).requires_grad)
'''
True
True
False
'''

如果我们想要修改 tensor 的数值,但是又不希望被 autograd 记录(即不会影响反向传播), 那么我么可以对 tensor.data 进行操作。

x = torch.ones(1,requires_grad=True)
​
print(x.data) # 还是一个tensor
print(x.data.requires_grad) # 但是已经是独立于计算图之外
​
y = 2 * x
x.data *= 100 # 只改变了值,不会记录在计算图,所以不会影响梯度传播
​
y.backward()
print(x) # 更改data的值也会影响tensor的值 
print(x.grad)
'''
tensor([1.])
False
tensor([100.], requires_grad=True)
tensor([2.])
'''
x = torch.ones(1,requires_grad=True)
​
print(x.data) # 还是一个tensor
print(x.data.requires_grad) # 但是已经是独立于计算图之外
​
y = 2 * x
x *= 100 # 直接对x操作会报错
​
y.backward()
print(x) # 
print(x.grad)
'''
tensor([1.])
False
---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
<ipython-input-42-9b61d3c7b33e> in <module>
      5 
      6 y = 2 * x
----> 7 x *= 100 #
      8 
      9 y.backward()

RuntimeError: a leaf Variable that requires grad is being used in an in-place operation.
'''
上一篇:验证误差反向传播算法


下一篇:【python实现卷积神经网络】全连接层实现