动手学深度学习-准备基础

动手学深度学习-准备基础

  • 动手学深度学习
    • 基础知识:
      • 第1章:深度学习背景
        • 起源:
          • 神经网络核心原则:
        • 发展:
        • 特点
          • 机器学习和深度学习的关系:
          • 端到端训练:
      • 第2章:动手学深度学习的预备知识
        • 算法操作:
        • 索引:
        • 改变形状:
        • 线性函数
        • 广播机制
        • 运算的内存开销
        • TENSOR和NUMPY的转换
          • Tensor转换为NumPy数组:
          • NumPy转换为Tensor:
        • 自动求梯度
          • Tensor

动手学深度学习

基础知识:

动手学深度学习-准备基础_第1张图片

第1章:深度学习背景

时间快,这块不是重点;要把动手编程变为重点。

机器学习是一门讨论各式各样的适用于不同问题函数形式,以及如何使用数据来有效地获取函数参数具体值的学科。深度学习是指机器学习中的一类函数,它们的形式通常为多层神经网络

起源:

自然法则,是从数据回归到自然定律,可以用线性模型完美表达的。(发现自然定律的过程,也可以认为是深度学习的过程。)

对于深度学习的认识,可以认为是数据分析的高度解读,将数据回归到规律上的过程。

赫布理论是感知机学习算法的原型,并成为随机梯度下降算法的基石:强化合意的行为、惩罚不合意的行为,最终获得优良的神经网络参数。

神经网络核心原则:
  • 交替使用线性处理单元与非线性处理单元,它们经常被称为“”。
  • 使用链式法则(即反向传播)更新网络的参数。

发展:

  • 优秀的容量控制方法,如丢弃法,靠在整个网络中注入噪声而达到的,如训练时随机将权重替换为随机的数字。
  • 注意力机制,使用了一个可学习的指针结构来构建出一个精妙的解决方法;(其在像机器翻译这样的任务中记忆整个句子,不如记忆指向翻译的中间状态的指针);这样容量储存空间会更大。
  • 记忆网络和神经编码器—解释器这样的多阶设计使得针对推理过程的迭代建模方法变得可能(允许重复修改深度网络的内部状态,好像处理器在计算过程中修改内存一样)
  • 生成对抗网络的发明 ,将采样部分替换成了任意的含有可微分参数的算法。这些参数将被训练到使辨别器不能再分辨真实的和生成的样本。(生成奔跑的斑马和生成名流的照片 )

特点

机器学习和深度学习的关系:
  • 机器学习研究如何使计算机系统利用经验改善性能
  • 深度学习是具有多级表示表征学习方法;表征学习关注如何自动找出表示数据的合适方式,以便更好地将输入变换为正确的输出。

深度学习模型也可以看作是由许多简单函数复合而成的函数。(通过多函数来表达复杂的变换)

端到端训练:

不是将单独调试的部分拼凑起来组成一个系统,而是将整个系统组建好之后一起训练。(自动优化的逐级过滤器)。

当数据多的时候,可以采用无参数模型(因为完全可以通过大数据来学习)

当数据少的时候,可以简化对现实的假设来得到实用的模型,采用含参数模型。

第2章:动手学深度学习的预备知识

知道如何使用笔记本运行代码

算法操作:

import torch
import numpy as np
#创建随机初始化的Tensor
x1 = torch.rand(5, 3)
print("随机初始化的Tensor:\n{}\n".format(x1))

#创建long型全为0的Tensor
x2 = torch.zeros(5, 3, dtype=torch.long)
print("long型全为0的Tensor:\n{}\n".format(x2))

#直接根据数据来构建的Tensor
x3 = torch.tensor([5.5, 3.3])
x4 = torch.tensor(np.array([5.5, 3.3]))
print("直接根据数据来构建的Tensor:\n{}\n".format(x3))
print("直接根据数据来构建的Tensor(numpy形式):\n{}\n".format(x4))

#通过先有Tensor来构建的Tensor
x = x2.new_ones(5, 3, dtype=torch.float64) 
print("通过先有Tensor来构建的Tensor:\n{}\n".format(x))

#指定新的数据类型;本来是ones,给变成random形式了
x= torch.randn_like(x, dtype=torch.float)
print("指定新的数据类型:\n{}\n".format(x))

y = torch.rand(5, 3)
print("y and x + y ")
print("y={}".format(y))
print("x + y ={}".format(x + y))

#通过先有Tensor来构建的Tensor
x = x2.new_ones(5, 3, dtype=torch.float64) 
print("通过先有Tensor来构建的Tensor:\n{}\n".format(x))

#指定新的数据类型;本来是ones,给变成random形式了
x= torch.randn_like(x, dtype=torch.float)
print("指定新的数据类型:\n{}\n".format(x))

#输出Tensor形状
print(x.size())
print(x.shape)

#修改Tensor的值
x = x2.new_ones(5, 3, dtype=torch.float64) 
print("通过先有Tensor来构建的Tensor:\n{}\n".format(x))
x[1][2] = 2
print("修改后的Tensor:\n{}\n".format(x))

#求导
x = torch.tensor([[1., -1.], [1., 1.]], requires_grad=True)
out = x.pow(4).sum()
out.backward()
x.grad

结果:

随机初始化的Tensor:
tensor([[0.2630, 0.5941, 0.1872],
        [0.1692, 0.8500, 0.2259],
        [0.3602, 0.0736, 0.3236],
        [0.8318, 0.0060, 0.9432],
        [0.8817, 0.4153, 0.0349]])

long型全为0的Tensor:
tensor([[0, 0, 0],
        [0, 0, 0],
        [0, 0, 0],
        [0, 0, 0],
        [0, 0, 0]])

直接根据数据来构建的Tensor:
tensor([5.5000, 3.3000])

直接根据数据来构建的Tensor(numpy形式):
tensor([5.5000, 3.3000], dtype=torch.float64)

通过先有Tensor来构建的Tensor:
tensor([[1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.]], dtype=torch.float64)

指定新的数据类型:
tensor([[-0.0822,  0.3507, -0.4749],
        [-0.6580,  0.9162,  0.1962],
        [-0.4497,  0.0201, -0.9021],
        [ 0.7282,  1.2726,  0.2614],
        [-1.5695,  1.0593,  0.1956]])

y and x + y 
y=tensor([[0.6761, 0.5520, 0.0738],
        [0.5443, 0.1203, 0.9336],
        [0.7933, 0.6119, 0.7786],
        [0.1704, 0.1668, 0.7125],
        [0.4866, 0.0854, 0.0205]])
x + y =tensor([[ 0.5939,  0.9027, -0.4011],
        [-0.1136,  1.0365,  1.1298],
        [ 0.3436,  0.6321, -0.1235],
        [ 0.8985,  1.4394,  0.9738],
        [-1.0828,  1.1447,  0.2161]])
索引:

tensor([0.9178, 1.3507, 0.5251])
tensor([0.9178, 1.3507, 0.5251])


索引:

索引出来的结果与原数据共享内存,也就是如果修改一个,另一个也会被修改;

#通过先有Tensor来构建的Tensor
x = x2.new_ones(5, 3, dtype=torch.float64) 
print("通过先有Tensor来构建的Tensor:\n{}\n".format(x))

#指定新的数据类型;本来是ones,给变成random形式了
x= torch.randn_like(x, dtype=torch.float)
print("指定新的数据类型:\n{}\n".format(x))

y = torch.rand(5, 3)
print("y and x + y ")
print("y={}".format(y))
print("x + y ={}".format(x + y))

#索引
y = x[0, :]
y +=1
print(y)
print(x[0, :])

结果:

通过先有Tensor来构建的Tensor:
tensor([[1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.]], dtype=torch.float64)

指定新的数据类型:
tensor([[-1.7176,  1.6462,  0.4919],
        [-1.3136,  0.2945, -0.3432],
        [ 0.5023,  0.7090, -0.4784],
        [ 2.0734, -1.2543, -1.2498],
        [-1.1179,  0.2308, -0.9198]])

torch.Size([5, 3])
torch.Size([5, 3])
通过先有Tensor来构建的Tensor:
tensor([[1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.]], dtype=torch.float64)

修改后的Tensor:
tensor([[1., 1., 1.],
        [1., 1., 2.],
        [1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.]], dtype=torch.float64)

如果想要不共享内存,可以使用clone;

#不想共享内存的索引
x_clone = x.clone()
y = x_clone[0, :]
y +=1
print("不共享内存的索引:\n")
print(y)
print(x[0, :])

结果:

不共享内存的索引:

tensor([1.9178, 2.3507, 1.5251])
tensor([0.9178, 1.3507, 0.5251])

其他的高级索引函数:
动手学深度学习-准备基础_第2张图片

改变形状:

用view()来改变形状,但是view()只是改变了观察张量的角度,但是数据部分仍然是共享的(即改变一个角度的张量,其他的也会跟着改变;就像《龙珠》中的天津饭的分身术一样)

#改变形状
print("改变形状:\n")
y = x.view(15)
z = x.view(-1, 5)
print("x.size={}\ny.size={}\nz.size={}".format(x.size(), y.size(), z.size()))

结果:

改变形状:

x.size=torch.Size([5, 3])
y.size=torch.Size([15])
z.size=torch.Size([3, 5])

item()将Tensor转变为Python number

x = torch.randn(1)
print(x)
print(x.item())

线性函数

函数 功能
trace 对角线元素之和(矩阵的迹)
diag 对角线元素
triu/tril 矩阵的上三角/下三角,可指定偏移量
mm/bmm 矩阵乘法,batch的矩阵乘法
addmm/addbmm/addmv/addr/badbmm… 矩阵运算
t 转置
dot/cross 内积/外积
inverse 求逆矩阵
svd 奇异值分解

广播机制

torch.range(start=1, end=6) 的结果是会包含end的,
而torch.arange(start=1, end=6)的结果并不包含end。

x = torch.arange(1,3).view(1, 2)
print("x={}".format(x))
y = torch.arange(1,4).view(3, 1)
print("y={}".format(y))
print("x + y ={}".format(x+y))

运算的内存开销

像y= x+y这样的运算会新开内存

x = torch.tensor([1, 2])
y = torch.tensor([3, 4])
id_before = id(y)
y = y + x
print(id(y) == id_before)#没加索引

可以通过索引的方式来进行替换操作,可以就可以指定结果到原来的y的内存里了

x = torch.tensor([1, 2])
y = torch.tensor([3, 4])
id_before = id(y)
y[:] = y + x
print(id(y) == id_before)#加索引的情况

还可以使用运算符全名函数中的out参数或者自加函数来达到以上结果

x = torch.tensor([1, 2])
y = torch.tensor([3, 4])
id_before = id(y)
y += x  #torch.add(x, y, out=y)
print(id(y) == id_before)

TENSOR和NUMPY的转换

Tensor转换为NumPy数组:

使用numpy()将Tensor转换为NumPy数组(他们之间是共享相同的内存,改变一个另一个随着变化)

#使用numpy()
a = torch.ones(5)
b = a.numpy()
print(a, b)

a+=1
print(a, b)
b+=1
print(a, b)
NumPy转换为Tensor:

使用from_numpy()将NumPy转换为Tensor(他们之间是共享相同的内存,改变一个另一个随着变化)

a = np.ones(5)
b = torch.from_numpy(a)
print(a, b)

a+=1
print(a, b)
b+=1
print(a, b)

使用torch.tensor()将NumPy数组转换为Tensor(该方法只是对数据进行拷贝,并不会再共享内存)

c = torch.tensor(a)
print(a, c)
a += 1
print(a, c)

自动求梯度

将Tensor的属性.requires_grad设置为TRUE,就可以跟踪在其上的所有操作,之后可以通过链式法则来进行梯度传播;完成计算后,可以调用.backward()来完成所有梯度的计算;此Tensor的梯度将累积到.grad属性中。
调用.detach()将其从跟踪记录中剥离出来;
with torch.no_grad()将不想被追踪的代码包裹起来。

Tensor

创建一个Tensor,并设置requires_grad=True(由于x是刚创建的值,所以grad_fn没有值)

x = torch.ones(2, 2, requires_grad=True)
print(x)
print(x.grad_fn)#none

添加运算

y = x + 2
print(y)
print(y.grad_fn)#
#复杂一点的操作
z = y * y * 3
out = z.mean()
print(z.grad_fn)#

对out进行求导:
动手学深度学习-准备基础_第3张图片

out.backward()
print(x.grad)

通过.requires_grad_()来用in-place的方式改变requires_grad属性:

a = torch.randn(2, 2)
print(a)
a = ((a * 3) / (a - 1))
print(a.requires_grad)
a.requires_grad_(True)
print(a.requires_grad)

grad在反向传播中是累加的,所以一般在反向传播之前进行梯度清零

out2 = x.sum()
out2.backward()
print(x.grad)

out3 = x.sum()
x.grad.data.zero_()
out3.backward()
print(x.grad)

不允许张量对张量求导,只允许标量对张量求导,求导结果是与自变量同形的张量(例如上面在求导时,都是mean,或sum等函数之后得到的标量)

x = torch.tensor([1.0, 2.0, 3.0, 4.0], requires_grad=True)
y = 2 * x
z = y.view(2, 2)
print(z)
v = torch.tensor([[1.0, 0.1], [0.01, 0.001]], dtype=torch.float)
z.backward(v)
print(x.grad)

中断梯度跟踪

x = torch.tensor(1.0, requires_grad=True)
y1 = x ** 2
with torch.no_grad():
    y2 = x ** 3
y3 = y1 + y2
print(x.requires_grad)#TRUE
print(y1.requires_grad)#TRUE
print(y2.requires_grad)#FALSE
print(y3.requires_grad)#TRUE

y3.backward()
print(x.grad)#只有y1有关的梯度才会回传

想要修改Tensor的值,但又不想被autograd记录(不影响反向传播),可以对tensor.data进行操作

x = torch.tensor(1.0, requires_grad=True)
print(x.data)
print(x.data.requires_grad)#False
y = 2 * x
x.data *= 100
y.backward()
print(x)#对x.data更改的值,也会保存在x中;tensor(100., requires_grad=True)
print(x.data)#tensor(100.)

你可能感兴趣的:(Python学习,深度学习,深度学习,人工智能)