d2l学习_第二章预备知识

x.1 Data Manipulation

数据操作。在Pytorch中常用的数据操作如下:

对于张量,即torch.Tensor类型的数据,你的任何操作都要把他想象成一个指针,因为等于运算符a=b,会将b的张量内存地址赋值给a。

'''torch.Tensor类型的基本使用'''

# 集中常见的初始化torch.Tensor的方法

import torch

# one dimension
x = torch.arange(12)
print(x, x.shape, x.dtype, x.numel(), )

# reshape
y = x.reshape(3, -1)
print(y)

# multi dimensions
a = torch.zeros((2, 3, 4))
b = torch.ones((2, 3, 4))
c = torch.randn((2, 3, 4))
d = torch.tensor([[2, 2, 2], [3, 3, 3]])
print(a, '\n', b, '\n', c, '\n', d)


# 运算符: 运算符的运算是按照元素进行的
e = a + b

# concat 拼接,指定拼接的dim
f = torch.cat((a, b), dim=0)
print(f)

# sum计算求和统计量
g = b.sum()
print(g)

# 判断位置是否相同,常用于做mask
k = a == b
print(k)

# 广播机制,在进行四则运算的时候,当矩阵形状不同时,会先扩展为形状相同再进行计算。但是很多情况下我并不知道怎么使用。常用的是矩阵加一个标量。
h = torch.arange(6).reshape(3, 2)
i = torch.arange(2).reshape(1, 2)
print(h)
print(i)
j = h+i
print(j)

# 切片和索引。同python中的list使用
a[0, 0, 0:3] = 7
print(a)

# 我们使用id()进行内存定位。Y=[expresion Y]会重新分配Y的内存;Y[:]=和Y+=都不会重新分配内存。建议多用后者,这样做可以减少内存开销。
before = id(y)
y = y + 1
print(id(y) == before)

before = id(y)
y += 1
print(id(y) == before)

before = id(y)
y[:] = y + 1
print(id(y) == before)

# 类型转换
l = x.numpy()
m = torch.tensor(l)
print(type(l), type(m))

# 提出tensor 的标量
n = torch.tensor([[1.]])
print(type(n.item()), type(float(n)))

x.2 Data Preprocessing

数据预处理。数据预处理常常使用Pandas库。

常用操作如下:

'''pandas的基本使用'''

import pandas as pd
import torch

# 存储数据/读取数据
import pandas as pd
data_file = "./_.csv"
data = pd.read_csv(data_file)
print(data)
data.to_csv(data_file)

# 创建Pandas DataFrame
DF_NAME = [
    "channel",
    "position",
    "dir_name",
]
# 创建空DataFrame
df_rows_num = 10
df = pd.DataFrame(
    data=None, 
    index=range(df_rows_num),
    columns=DF_NAME,
)
print(df)

# 新增新的一行数据
# add one row - method 1: generage a dictionary, then using .loc[]  || recommanded ||
df_one_row_dict = {
    "channel":  "retardance",
    "position": 4,
    "dir_name": "None",
}
df.loc[0, :] = df_one_row_dict
# add one row - method 2: generate one dataframe, then using concat.
df_one_row_dict = {
    "channel":  ["retardance"],
    "position": [4],
    "dir_name": ["None"],
}
df_one_row = pd.DataFrame(df_one_row_dict)
df = pd.concat([df, df_one_row], axis=0)
print(df)

# 筛选数据
inputs, targets = data.iloc[:, 0:2], data.iloc[:, 2]
inputs = pd.get_dummies(inputs, dummy_na=True)
print(inputs)

# 类型转换 - 转为numpy
numpy_data = df.to_numpy()
print(numpy_data)
# 转为tensor: 用.values只取值(将index剔除);用.astype("float64")指定ndarray的数据类型。
df_position = df.loc[:, "position"]
df_position = df_position.dropna(axis=0, how="all")
print(df_position)
torch_data = torch.tensor(df_position.values.astype("float64"), dtype=torch.float64)    # ndarray转换类型
print(torch_data)

x.3 Linear Algebra

在线性代数这个阶段,我们首先需要知道scalars标量, vectors向量, matrices矩阵, tensors张量以及它们的基本操作例如reduction降维, non-reduction sum非降维求和, dot products点积, matrix-vector products矩阵向量积, Matrix-Matrix Multiplication矩阵-矩阵乘法, Norms范数

从scalars到tensors是升维的过程,其中scalar是0维张量,vector是1维,matrix是2维,而tensor是多维。例如想象立方体,除了长宽还有一个维度用来表示厚度;又如JPG图片的解释形式,三个维度表示R, G, B。

对于张量,它的数加a是各元素都加a,数乘同理。而对于两个相同shape的张量,张量相加就是逐元素相加,hadamard product哈马达积就是逐元素相乘(逐元素指的是对应位置的元素)。

对于张量的降维是本章难点,首先维度的排列是从第0维到第n维,例如[[]]具有两维度,从外层至内层依次是第0维,第1维。而用来降维的函数有sum()和mean(),其中可以指定维度,如axis=0即在第0维上降维squeeze掉,如下:

请添加图片描述

巧记:在哪个维度进行sum,即将该维度上所有元素相加,如[[0, 1], [1, 2]]在0维度相加,即将0维所有元素[0, 1]和[1, 2]相加,最终变成了[1, 3]

点积即投影,对应元素相乘再相加。矩阵-向量乘和矩阵-矩阵乘即数学上的矩阵乘法。

范数常见于描述距离,常见有L1范数MAE,L2范数MSE,Lp范数的表达如下:

请添加图片描述

附录该小节代码:

'''一些数学知识,关于线性代数的'''

# 统计学中一行数据叫一个样本,一列数据叫一个特征feature,最后一列往往是标签label

import torch

# 标量 - 指0维数据
a = torch.tensor(1.)
print(a)

# 向量 - 指1维数据
b = torch.arange(12)
print(b, b[7], len(b), b.shape)

# 矩阵 - 指多维数据
c = torch.arange(12).reshape(3, 4)
print(c)
# 矩阵转置
# d = torch.transpose(c, 1, 0)
d = c.transpose(1, 0)
print(d)

# 两个矩阵的哈马达积用*
e = torch.arange(12, dtype=torch.float32).reshape(3, 4)
# f = e         # id 相同
# f = e.clone() # id 不同
f = e + 0       # id 不同
print(id(e) == id(f))
g = f * e   # 哈马达积
print(g)

# 矩阵求和sum(); 求均值mean(); 
# 你除了知道这两个API的作用外,你还应该知道这两个函数是用来降维的。
h = g.sum(axis=[0, 1])
i = g.mean(axis=[0, 1])
print(h, i)

# 两个向量的点积用.dot()
j = torch.ones(4, dtype=torch.float32)
k = j.clone()
l = j.dot(k)
print(l)

# 矩阵-向量乘法用.mv
m = torch.arange(12).reshape(6, 2)
n = torch.ones(2, dtype=torch.long) # shpae=[2, 1, 1, 1, ...]补全是往后补1
print(n)
o = m.mv(n)
print(o)

# 矩阵-矩阵乘法用.mm
p = m.transpose(1, 0)
q = m.mm(p)
print(q)

# 向量二范数(又叫L2范数)就是平方和的平方根, 用norm()二范数的英文
r = torch.tensor([3., 4.])
s = r.norm()
print(s)

# 向量一范数(又叫L1范数)就是绝对值的和
t = r.abs().sum()
print(t)

# 矩阵的Frobenius范数类似向量的二范数,就是各个元素平方和的平方根
u = torch.randn(3, 4)
v = u.norm()
print(v)

x.4 Calculus

在微积分中最重要的就是基于链式法则的偏导数计算,将求得的偏导连起来就是梯度方向,梯度即fx下降最快的反方向,如下:

请添加图片描述

引入微积分的例子只是说明在Pytorch中的tensor是会自动微分的,当你调用y.backward()时候会自动计算y的梯度并更新模型的存储梯度信息的矩阵,以至于在后面的optimizer.step()中更新模型的存储权重信息的矩阵。

关于微积分的代码部分:

'''关于微积分的学习'''

# 我们往往使用python进行参数的训练。在使用c/c++将模型部署到硬件/软件上。

# 微分。用导数定义求导。
def f(x):
    return 3 * x ** 2 - 4 * x

def numerical_lim(f, x, h):
    return (f(x + h) - f(x)) / h

h = 0.1
for i in range(5):
    print(f'h={h:.5f}, numerical limit={numerical_lim(f, 1, h):.5f}') 
    h *= 0.1


# torch或者tf相比较于numpy好用的地方有两点, 1. 分别是可以传入GPU进行计算 2. 可以自动微分(automatic differentiation)
# 其中torch会根据搭建的模型构建一个计算图(computational graph)来跟踪计算; 而反向传播(backpropagate)则是根据计算图计算每个参数的偏导数。
import torch

x = torch.arange(4.)
x.requires_grad_(True)  # 对x开启梯度跟踪
y = 2 * x.dot(x)    # 搭建好了computational graph
y.backward()    # backpropagate
print(x.grad)   # 输出梯度
print(x.grad == 4 * x)  # 判断梯度对不对

# 将张量的梯度设置为0用.grad.zero_()。否则会梯度爆炸。而这个梯度清零经常包围在backward()前后,即:
# optimizer.zero_grad()
# loss.backward()   # 这里的loss相当于你的目标函数y = 2 * x.dot(x)
# optimizer.step()
x.grad.zero_()  # 梯度清零
y = x.sum()
y.backward()
print(x.grad)

# 将张量从计算图中分离出来使用.detach()
x.grad.zero_()
y = x * x 
u = y.detach()
z = u * x   

z.sum().backward() # 这里在x的backpropagate,即计算z关于x的偏导数时候,因为.detach()的存在,到u就截止了。
print(x.grad == u)
# --- 这里你一定觉得很奇怪为什么要加sum(),这是因为backward()这个函数只对标量进行计算。当你的计算结果是向量的时候,就得使用sum()或者mean()进行降维,常使用sum().
# 参考链接:https://zhuanlan.zhihu.com/p/427853673

x.5 Probability and Statistics

概率论与数理统计将再开个大的章节进行学习。Maybe 线性代数也是如此。

'''概率论与统计学的知识'''

# 随机变量

# 联合概率

# 条件概率

# 全概率公式

# 贝叶斯公式

# 独立性

# 期望和方差
# --- 在这里我们需要注意的是期望并不等于均值。期望是随变取值乘以随变取值的概率,均值就是随变的平均值。
# --- 为什么我们常常认为期望等于均值呢?是因为我们经常碰到的是高斯分布(正态分布),正态分布的是数学期望等于μ;或者当随便取值等概率的时候,期望也等于均值。

x.6 Pythonic

常见用dir()来查看module中有哪些func, class, attributes等;使用help()来查看API使用方法。查阅文档很有帮助的函数包括如下:

import torch

dir(torch)
help(torch.ones)
'''一些很pythonic的东西'''

# 查看一个module脚本文件有什么函数,类,全局变量等。可以使用dir(file_name) | built-in function

# 查看帮助,一个函数怎么调用等可以使用help(function_name)
# 参考https://zhuanlan.zhihu.com/p/263351646

x.7 二刷的Jupyter脚本

请添加图片描述

请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值