(1)预备知识

目录

1.1 基础知识

1.1.1 入门 

 1.1.2 运算

 1.1.3 广播机制

1.1.4 索引和切片

1.1.5 转换为其他python对象

1.2 数据预处理

1.3 线性代数

1.4 微分

1.5 自动求导

1.6 概率


1.1.1 入门 

import torch 


# 使用arange创建一个行向量x
x = torch.arange(12)

# 访问张量的形状(沿每个轴的长度)
x.shape

# 张量中元素的总数number of element
x.numel()

# 想要改变张量的形状而不改变元素数量和元素值
# 其中,可以设置其中维度为-1,来自动推断维度
X = x.reshape(3,4)
X = x.reshape(-1,4)

# 使用全0数字初始化矩阵
torch.zeros((2,3,4))
# 使用全1数字初始化矩阵
torch.ones((2,3,4))

# 每个元素均值为0,标准差为1,形状(3,4)的张量
torch.randn(3,4)

# 通过列表初始化
torch.tensor([1,2,3,4])

 1.1.2 运算

#对于任意具有相同形状的张量,我们可以进行+-*/和**的元素基本运算
x + y
x - y
x * y
x / y
x ** y

# 按元素的求幂运算(e为底)(得到和x一样大小的e为底,x元素为指数的张量)
torch.exp(x)

# 多个张量的连结
X = torch.arange(12,dtype=torch.float32).reshape((3,4))
Y = torch.tensor([[1,2,3,4],[5,6,7,8],[9,10,11,12]])
# 行连结
torch.cat((X,Y),dim=0)
# 列连结
torch.cat((X,Y),dim=1)

# 当进行逻辑运算时,得到的也是逻辑结果的张量
X == Y
X > 12

# 对张量的所有元素求和会得到只有一个元素的张量
X.sum()

 1.1.3 广播机制

在某些情况下,即使形状不同,我们可以调用广播机制执行元素操作。

首先,通过适当复制元素来扩展一个或两个数组,以便在转换之后,两个张量具有相同的形状。

其次,对生成的数组按元素操作。

可广播的张量需满足以下规则:

        1.每个张量至少一个维度

        2.从尾部开始,维度尺寸要么相等,要么其中一个张量维度尺寸为1,要么其中一个张量不存在这个维度

1.1.4 索引和切片

# X的最后一个元素
X[-1]

# 第二个和第三个元素
X[1:3]

# 通过索引将元素写入矩阵
X[1,2] = 9
X[0:2,:] = 12

1.1.5 转换为其他python对象

A = X.numpy()

B = torch.tensor(A)

# 要将大小为1的张量转换为python的标量,可以调用item函数或是python的内置函数
a = torch.tensor([5])

a.item()

float(a)

int(a)

1.2 数据预处理

# 操作系统接口模块
import os 
# os.path.join即简单的路径拼接
# exist_ok如果是False,那么如果目录已经存在则会Error
os.makedirs(os.path.join('..','data'),exist_ok=True)    #用于创建多层目录
data_file=os.path.join('..','data','house_tiny.csv')
with open(data_file,'w') as f:
    f.write('NumRooms,Alley,Price\n') # 列名
    f.write('NA,Pave,127500\n') # 每行表示一个数据样本
    f.write('2,NA,106000\n')
    f.write('4,NA,178100\n')
    f.write('NA,NA,140000\n')

# 导入pandas包调用read_csv函数,数据集四行三列,每行描述了房间数量(“NumRooms”)、巷子类型
# (“Alley”)和房屋价格(“Price”)。
import pandas as pd

data = pd.read_csv(data_file)
print(data)

# 处理缺失值
# loc和iloc都是对pandas DataFrame进行切片索引
# loc是通过字符型标签获得数据
# iloc和list一样通过索引获得数据
inputs,outputs = data.iloc[:,0:2],data.iloc[:,2]
inputs = inputs.fillna(inputs.mean())
print(inputs)

# 对于inputs中的类别值,pandas可以自动将此列转换为两列“Alley_Pave”和“Alley_nan”。巷子类型
# 为Pave会将“Alley_Pave”的值设为1,“Alley_nan”值设为0。get_dummies是将拥有不同值的变量转换
# 为0/1数值。
# 如果dummy_na = False表示忽略空缺值
inputs = pd.get_dummies(inputs, dummy_na=True)
print(inputs)

#转换为张量格式
import torch
X,y = torch.tensor(inputs.values),torch.tensor(outputs.values)

1.3 线性代数

标量:

import torch

x = torch.tensor([3.0])
y = torch.tensor([2.0])

x + y
x * y
x / y
x ** y

向量:

x = torch.arange(4) # tensor([0,1,2,3])
x[3]                # tensor(3)

# 长度,维度和形状
len(x)            # 4
x.shape             # torch.Size([4])

矩阵:

# 创建矩阵
A = torch.arange(20).reshape(5,4)

# 矩阵转置
A.T

张量:

# 创建张量
X = torch.arange(24).reshape(2,3,4)

A = torch.arange(20,dtype=torch.float32).reshape(5,4)
# 克隆张量A
B = A.clone()

# 元素按位运算
A * B
a = 2
a + X

# 降维
x = torch.arange(4,dtype=torch.float32)
x.sum()
# 默认情况下调用求和函数降低张量维度
# 可以指定某个轴的和
A_sum_axis0 = A.sum(axis=0)
A_sum_axis1 = A.sum(axis=1)
# 求平均值
A.mean()
A.sum()/A.numel()

# 非降维求和
sum_A = A.sum(axis=1,keepdims=True)
# 计算沿某一轴的累积总和
A.cumsum(axis=0) # 行

# 点积
y = torch.ones(4,dtype = torch.float32)
torch.dot(x,y)
# 其实就是按元素乘法进而求和来得到向量的卷积
torch.sum(x*y)

# 矩阵-向量积
# 代码中使用张量表示矩阵-向量积,我们使用与点积相同的dot函数,当我们为矩阵A和向量x调用
np.dot(A,x)时,即执行矩阵-向量积
torch.mv(A,x)

# 矩阵-矩阵积
torch.mm(A,B)

# 计算向量的范数
# 计算L2范数(根号下平方和)
u = torch.tensor([3.0,-4.0])
torch.norm(u)   # tensor(5)
# 计算L1范数(绝对值求和)
torch.abs(u).sum()

1.4 微分

# 使用svg格式在Jupyter中显示绘图
def use_svg_display(): 
    # 设置显示格式为svg
    display.set_matplotlib_formats('svg')

# 设置matplotlib图表大小
def set_figsize(figsize=(3.5,2.5)):
    use_svg_display()
    d2l.plt.rcParams['figure.figsize'] = figsize

# 设置由matplotlib生成图表的轴的属性
def set_axes(axes, xlabel, ylabel, xlim, ylim, xscale, yscale, legend):
    axes.set_xlabel(xlabel)
    axes.set_ylabel(ylabel)
    axes.set_xscale(xscale)
    axes.set_yscale(yscale)
    axes.set_xlim(xlim)
    axes.set_ylim(ylim)
    if legend:
        axes.legend(legend)
    axes.grid()

# 绘制曲线
def plot(X, Y=None,xlabel=None,ylabel=None,legend=None,xlim=None,ylim=None,
xscale='linear',yscale='linear',
fmts=('-','m--','g-.','r:'),figsize=(3.5,2.5),axes=None):
    if legend is None:
        legend = []
    set_figsize(figsize)
    axes = axes if axes else d2l.plt.gca()
    #如何X有一个轴输出True
    def has_one_axis(X):
        return (hasattr(X,"ndim") and X.ndim == 1 or isinstance(X,list) and not 
hasattr(X[0],"__len__"))
    if has_one_axis(X):
        X = [X]
    if Y is None:
        X,Y = [[]]*len(X),X
    elif has_one_axis(Y):
        Y = [Y]
    if len(X) != len(Y):
        X = X * len(Y)
    axes.cla()
    for x,y,fmt in zip(X,Y,fmts):
        if len(x):
            axes.plot(x,y,fmt)
        else:
            axes.plot(y,fmt)
    set_axes(axes,xlabel,ylabel,xlim,ylim,xscale,yscale,legend)

绘制函数u = f(x)及其在x = 1处的切线y = 2x - 3

x = np.arange(0,3,0.1)
plot(x, [f(x), 2*x-3], 'x', 'f(x)', legend=['f(x)','Tangent line (x=1)'])

1.5 自动求导

# 对y=2xTx关于列向量x求导
import torch
x = torch.arange(4.0)
# 在计算y关于x的梯度之前,需要一个地方存储梯度,重要的是,我们不会每次对参数求导都分配新的
内存,因此会成千上万次更新相同的参数,每次分配新的内存会很快将内存耗尽
x.requires_grad_(True) #等价于 x = torch.arange(4.0,requires_grad=True)
x.grad # 默认值为None
# 计算y
y = 2 * torch.dot(x,x)
# 调用反向传播自动计算y关于x每个分量的梯度
y.backward()
# 打印梯度
x.grad

# 这时候如果计算x的另一个函数
# 默认情况下,pytorch会累积梯度,我们需要清楚之前的值
x.grad.zero_()
y = x.sum()
y.backward()
x.grad    # tensor([1,1,1,1])

如果y不是标量,那么向量y关于向量x的导数最自然解释是一个矩阵。而对于高阶和高维y和x,求导的结果可以是一个高阶张量。有待深入研究

# 对于非标量调用backward需要传入一个gradient参数,该参数指定微分函数关于self的梯度。在例子中
只是想求偏导数的和,所以传递1的梯度合适的
x.grad.zero_()
y = x * x
# 等价于y.backward(torch.ones(len(x)))
y.sum().backward()
x.grad

分离计算:想计算z关于x的梯度,希望视y为常数,并只考虑x在y被计算后的作用。

x.grad.zero_()
y = x * x
u = y.detach()
z = x * u
z.sum.backward()
x.grad == u        #[True,True,True,True]

x.grad.zero_()
y.sum().backward()
x.grad == 2 * x    #[True,True,True,True]

python控制流的梯度计算:

即使构建函数的计算图需要通过python控制流,我们仍然可以计算得到变量的梯度。

def f(a):
    b = a * 2
    while b.norm() < 1000:
        b = b * 2
    if b.sum() > 0:
        c = b
    else:
        c = 100 * b
    return c
# 计算梯度
a = torch.randn(size=(),requires_grad=True)
d = f(a)
d.backward()

a.grad == d/a  # True

对于任何a,存在常量k使得f(a) = k*a,其中k的值取决于输入a,因此d/a可以验证梯度是否正确。

1.6 概率

%matplotlib inline
import torch
from torch.distributions import multinomial
from d2l import torch as d2l
# 为了抽取一个样本我们只需要传入一个概率向量
fair_probs = torch.ones([6])/6    # tensor([1,1,1,1,1,1])
# 1为取样次数,fair_probs为概率向量
multinomial.Multinomial(1,fair_probs).sample()

# 模拟1000次投掷
counts = multinomial.Multinomial(1000, fair_probs).sample()
counts/1000 # 相对频率作为估计值 

# 随着时间推移收敛到真实概率
counts = multinomial.Multinomial(10,fair_probs).sample((500,))
# 层层叠加
cum_count = count.cumsum(dim=0)
estimates = cum_counts / cum_counts.sum(dim=1,keepdims=True)

d2l.set_figsize((6,4.5))
for i in range(6):
    d2l.plt.plot(estimate[:,i].numpy(),
                label=("P(die=" + str(i+1) + ")"))
d2l.plt.axhline(y=0.167, color='black', linestyle='dashed')
d2l.plt.gca().set_xlabel('试验次数')
d2l.plt.gca().set_ylabel('估算概率')
d2l.plt.legend()

你可能感兴趣的:(动手学深度学习,python,深度学习)