AkiraZheng's Time.

动手学深度学习01

Word count: 1.4kReading time: 6 min
2022/04/17

前言

本章内容为动手学深度学习-预备知识章节

本章内容源自d2l代码包中的chapter_preliminaries文件夹

课程源自 动手学深度学习在线课程

代码运行在Google的Colab平台中

数据操作

1
import torch
1
2
3
4
x = torch.arange(15)
print(x)
print(x.shape)
print(x.numel())
1
2
x = x.reshape(3,5)
print(x)
1
print(torch.ones((2,3,4)))
1
2
3
4
5
6
7
8
9
# 二维数据
y = torch.tensor([[2,1,4,3], [1,2,3,4], [4,3,2,1]])
print(y)
print(y.size())

# 三维数据
y = torch.tensor([[[2,1,4,3], [1,2,3,4], [4,3,2,1]]])
print(y)
print(y.size())
1
2
3
4
5
x = torch.arange(12, dtype=torch.float32).reshape((3,4))  # 【3,4】
print(x)

y = torch.tensor([[2.0,1,4,3], [1,2,3,4], [4,3,2,1]]) # 【3,4】
torch.cat((x, y), dim=0), torch.cat((x, y), dim=1) # dim=0,按行合并两个矩阵; dim=1, 按列合并两个矩阵
1
x.sum()

广播机制–同一纬度不同大小矩阵的相加机制

如对于一个二维的(3,1)大小矩阵跟(1,2)大小矩阵

会把(3,1)扩展出相同的一列变为(3,2)

同理(1,2)扩展为(3,2)

1
2
3
4
5
6
x = torch.arange(3).reshape((3,1))
y = torch.arange(2).reshape((1,2))

print(x)
print(y)
print(x+y)

Python矩阵拆分

1
2
3
4
5
6
x = torch.arange(12).reshape((3,4))
print(x)
print(x[-1]) # 取出倒数第一行数据
print(x[:,-1]) # 取出倒数第一列数据
print(x[0:2]) # 选取前两行
print(x[2,3])

内存分配问题

id()相当于c语言的指针

元素赋值不改变地址,整个数组赋值会改变地址

1
2
3
4
5
6
7
8
9
10
11
12
13
x = torch.arange(12).reshape((3,4))
y = torch.arange(12).reshape((3,4))

before = id(y)
y[:] = y+x
print(id(y)==before)
y = y-x # 对y进行操作会改变地址内容,产生了一个新的y
print(id(y)==before)

z = torch.zeros_like(y)
print('id(z):', id(z))
z[:]= x + y # 对z进行操作不会改变地址内容,是对元素进行赋值
print('id(z):', id(z))

更换张量

1
2
3
4
5
6
A = x.numpy()     # 转换为Numpy的张量
B = torch.tensor(A) # 转换为torch的张量
print(type(A), type(B))

a = torch.tensor([3.5])
print(a, a.item(), float(a), int(a)) # 转换为item标量

数据预处理

创建、写入CSV文件 – os

  • 创建文件夹:os.makedirs()

  • 创建csv文件:os.path.join()

  • 写入内容:

    with open() as f:

    f.write()

1
2
3
4
5
6
7
8
9
10
11
12
import os

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('NumRooma,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')

print(data_file)

加载csv原数据集 – pandas

  • read读入文件:

    pd.read_csv()

1
2
3
import pandas as pd
data = pd.read_csv(data_file)
data

处理缺失数据 – .fillna(插值)

常用插值或删除处理缺失数据

  • 取csv表格的某一行或列:

    .iloc[ ]

  • 字符串缺失

    字符串缺失的可以将字符串分为多个类别,用1-0表示

    .get_dummies()

1
2
3
input, output = data.iloc[:, 0:2], data.iloc[:, 2]
input = input.fillna(input.mean()) # 用均值插值
input
1
2
input = pd.get_dummies(input, dummy_na=True)
input

将csv数值型表格转换成tensor格式

  • 需要在csv表格nan数据都被处理成数值后才可以转换torch.tensor()
1
2
3
x, y = torch.tensor(input.values), torch.tensor(output.values)
print(x, y)
print(x.dim()) # 查看tensor的维度

线性代数

矩阵转置

  • 对称矩阵的转置等于本身

    .T

  • 克隆张量 – 重新分配内存

    B=A是建立view,改变B时A也会变

    B=A.clone()是重新分配内存,改变B时A不会改变

  • axis

    axis=0是按行(第一维度)处理,axis=1是按列(第二维度)处理

范数计算

  • 向量的$L_2$范式 – 求元素的平方和的平方根

    torch.norm()

  • 向量的$L_1$范式 – 求元素的绝对值之和

    torch.abs(u).sum()

  • 矩阵的$F$范数 – 矩阵元素的平方和的平方根

    torch.norm(u)

计算和、均值

  • 求和

    .sum(axis=)

  • 求均值

    .mean(axis=)

矩阵乘法

  • 矩阵×向量

    torch.mv()

  • 矩阵×矩阵

    torch.mm()

1
2
3
x = torch.arange(12).reshape(3,4)
print(x)
print(x.T)
1
2
y = x.clone()
y
1
2
u = torch.tensor([3.0,4.0])
torch.norm(u), torch.abs(u).sum()
1
2
A = torch.arange(20*2).reshape(2,5,4)
A, A.sum(axis=0), A.sum(axis=1), A.sum(axis=2), A.sum(axis=[0, 1])
1
2
3
4
5
6
7
8
9
10
A = torch.arange(20).reshape(5, 4) # 5*4的矩阵
B = torch.arange(4)

print(A)
print(B)
print(torch.mv(A, B))

B = torch.arange(12).reshape(4,3)
print(B)
print(torch.mm(A, B))
1
2
3
A = torch.arange(20).reshape(5, 4) # 5*4的矩阵
B = torch.arange(4)
len(A), len(B), A.numel(), B.numel()

微积分

标量对列向量求导:求解结果转置为行向量

列向量对标量求导:求解结果为列向量

由于loss通常是标量,因此深度学习中一般对标量进行求导,而不对矩阵或向量求导

自动微分

  • 存储梯度

    requires_grad_(True)

  • 反向传播函数计算y关于x的每个分量的梯度

    .backward()

  • 清除x累积的梯度,将梯度清为0

    .grad.zero_()

1
2
3
x = torch.arange(4.0, requires_grad=True)
# x.requires_grad_(True)
x.grad
1
2
y = 2 * torch.dot(x, x) # y=x^2
print(y)
1
2
y.backward()
x.grad == 4 * x
1
2
3
4
x.grad.zero_()  # 清除累积的梯度记录
y = x.sum()
y.backward()
x.grad == 1
1
2
3
4
x.grad.zero_()
y = x * x
y.sum().backward()
x.grad == 2 * x
1
2
3
4
5
6
x.grad.zero_()
y = x * x
u = y.detach() # 此时u的值=y,但是不与x建立传递关系,仅表示为普通常数
z = u * x
z.sum().backward()
x.grad == u
1
2
3
4
5
6
7
8
9
10
11
12
13
14
def f(a):
b = 2 * a
while b.norm()<1000:
b = b * 2
if b.sum()>0:
c = b
else:
c = 100 * b
return c

a = torch.rand(size=(), requires_grad=True)
d = f(a)
d.backward()
a.grad == d/a
CATALOG
  1. 前言
  2. 数据操作
    1. 广播机制–同一纬度不同大小矩阵的相加机制
    2. Python矩阵拆分
    3. 内存分配问题
    4. 更换张量
  3. 数据预处理
    1. 创建、写入CSV文件 – os
    2. 加载csv原数据集 – pandas
    3. 处理缺失数据 – .fillna(插值)
    4. 将csv数值型表格转换成tensor格式
  4. 线性代数
    1. 矩阵转置
    2. 范数计算
    3. 计算和、均值
    4. 矩阵乘法
  5. 微积分
    1. 自动微分