详细请参考教学文档 https://zh.d2l.ai/chapter_preliminaries/ndarray.html#id2
N维数组是机器学习和神经网络的主要数据结构
0-d(标量) 1.0 一个类别
1-d(向量) [...] 一个特征向量
2-d(矩阵) [[...]] 一个样本-特征矩阵
3-d [[[...]]] RGB图片(宽x高x通道)
4-d[ [[[[....]]]] 一个RGB图片批量(批量大小x宽x高x通道)
5-d [[[[[......]]]]] 一个视频批量(批量大小x时间x宽x高x通道)
一个元素:[1,2]
一行:[1,:]
一列:[:,2]
子区域:[1:3,1:]或者[::3,::2]
基本数学运算、广播、索引、切片、内存节省和转换其他Python对象
操作 |
说明 |
x = torch.arange(12) |
使用 arange 创建一个行向量 x |
x.shape |
通过张量的shape属性来访问张量(沿每个轴的长度)的形状 |
x.numel() |
张量中元素的总数 |
X = x.reshape(3, 4) |
要想改变一个张量的形状而不改变元素数量和元素值,可以调用reshape函数 |
torch.zeros((2, 3, 4)) |
使用全0、全1、其他常量,或者从特定分布中随机采样的数字 |
torch.ones((2, 3, 4)) |
创建一个形状为(2,3,4)的张量,其中所有元素都设置为1 |
torch.randn(3, 4) |
通过从某个特定的概率分布中随机采样来得到张量中每个元素的值 |
torch.tensor([[2, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]]) |
通过提供包含数值的Python列表(或嵌套列表),来为所需张量中的每个元素赋予确定值 |
x = torch.tensor([1.0, 2, 4, 8]) y = torch.tensor([2, 2, 2, 2]) x + y, x - y, x * y, x / y, x ** y |
常见的标准算术运算符(+、-、*、/和**)都可以被升级为按元素运算 |
torch.exp(x) |
求幂 |
X = torch.arange(12, dtype=torch.float32).reshape((3,4)) Y = torch.tensor([[2.0, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]]) torch.cat((X, Y), dim=0), torch.cat((X, Y), dim=1) |
把多个张量连结(concatenate)在一起,dtype表示数据类型,dim=0表示沿行连接两个矩阵,dim=1表示按列连接两个矩阵 |
X == Y |
通过逻辑运算符构建二元张量 |
X.sum() |
对张量中的所有元素进行求和,会产生一个单元素张量 |
a = torch.arange(3).reshape((3, 1)) b = torch.arange(2).reshape((1, 2)) a + b |
即使形状不同,我们仍然可以通过调用 广播机制(broadcasting mechanism)来执行按元素操作,将两个矩阵广播为一个更大的 3×2 矩阵 |
X[-1], X[1:3] |
可以用[-1]选择最后一个元素,可以用[1:3]选择第二个和第三个元素 |
X[1, 2] = 9 |
通过指定索引来将元素写入矩阵 |
X[0:2, :] = 12 |
为多个元素赋值相同的值 |
A = X.numpy() B = torch.tensor(A) |
转换为NumPy张量 |
a = torch.tensor([3.5]) |
将大小为1的张量转换为Python标量 |
节省内存操作中,注意区分以下两个,一个正确一个错误
before = id(Y)
Y = Y + X
id(Y) == before #False
before = id(X)
X += Y
id(X) == before #True
在实际操作过程中,也可以使用如下方式进行节省内存操作
Z = torch.zeros_like(Y)
print('id(Z):', id(Z)) #id(Z): 1576226143744
Z[:] = X + Y
print('id(Z):', id(Z)) # id(Z): 1576226143744
详细请参考教学文档 https://zh.d2l.ai/chapter_preliminaries/pandas.html
创建一个人工数据集,并存储在CSV(逗号分隔值)文件 ../data/house_tiny.csv中
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('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')
os.makedirs(name, mode=0o777, exist_ok=False)
作用
用来创建 多层目录(单层请用os.mkdir)
参数说明
name:你想创建的目录名
mode:要为目录设置的权限数字模式,默认的模式为 0o777 (八进制)。
exist_ok:是否在目录存在时触发异常。如果exist_ok为 False(默认值),则在目标目录已存在的情况下 触发FileExistsError异常;如果exist_ok为 True,则在目标目录已存在的情况下 不会触发FileExistsError异常。
os.path.join(path1[, path2[, ...]]) 把目录和文件名合成一个路径
从创建的CSV文件中加载原始数据集
# 如果没有安装pandas,只需取消对以下行的注释来安装pandas
# !pip install pandas
import pandas as pd
data = pd.read_csv(data_file)
print(data)
"""
NumRooms Alley Price
0 NaN Pave 127500
1 2.0 NaN 106000
2 4.0 NaN 178100
3 NaN NaN 140000
"""
为了处理缺失的数据,典型的方法包括插值法和删除法,其中插值法用一个替代值弥补缺失值,而删除法则直接忽略缺失值。在这里我们选用的是插值法。
通过位置索引iloc,我们将data分成inputs和outputs, 其中前者为data的前两列,而后者为data的最后一列。 对于inputs中缺少的数值,我们用同一列的均值替换“NaN”项。
inputs, outputs = data.iloc[:, 0:2], data.iloc[:, 2]
inputs = inputs.fillna(inputs.mean()) #mean()函数功能:取平均值
print(inputs)
"""
NumRooms Alley
0 3.0 Pave
1 2.0 NaN
2 4.0 NaN
3 3.0 NaN
"""
[对于inputs中的类别值或离散值,我们将“NaN”视为一个类别。] 由于“巷子类型”(“Alley”)列只接受两种类型的类别值“Pave”和“NaN”, pandas可以自动将此列转换为两列“Alley_Pave”和“Alley_nan”。 巷子类型为“Pave”的行会将“Alley_Pave”的值设置为1,“Alley_nan”的值设置为0。 缺少巷子类型的行会将“Alley_Pave”和“Alley_nan”分别设置为0和1。
inputs = pd.get_dummies(inputs, dummy_na=True)
print(inputs)
"""
NumRooms Alley_Pave Alley_nan
0 3.0 1 0
1 2.0 0 1
2 4.0 0 1
3 3.0 0 1
"""
pandas.get_dummies参数详解
data : array-like, Series, or DataFrame 输入的数据
prefix : string, get_dummies转换后,列名的前缀,默认为None
columns : 指定需要实现类别转换的列名 否则转换所有类别性的列
dummy_na : bool, default False 增加一列表示空缺值,如果False就忽略空缺值
drop_first : bool, default False 获得k中的k-1个类别值,去除第一个,防止出现多重共线性
现在inputs和outputs中的所有条目都是数值类型,它们可以转换为张量格式。
import torch
X, y = torch.tensor(inputs.values), torch.tensor(outputs.values)
print(X,'\n', y)
"""
tensor([[3., 1., 0.],
[2., 0., 1.],
[4., 0., 1.],
[3., 0., 1.]], dtype=torch.float64)
tensor([127500, 106000, 178100, 140000])
"""
详细请参考教学文档 https://zh.d2l.ai/chapter_preliminaries/linear-algebra.html
标量由只有一个元素的张量表示,其中标量变量由普通小写字母表示(例如, 、 和 )
下面的代码将实例化两个标量,并执行一些熟悉的算术运算,即加法、乘法、除法和指数。
import torch
x = torch.tensor(3.0)
y = torch.tensor(2.0)
x + y, x * y, x / y, x**y
"""
(tensor(5.), tensor(6.), tensor(1.5000), tensor(9.))
"""
可以被视为标量值组成的列表,向量通常记为粗体、小写的符号 (例如,、和)。
人们通过一维张量表示向量。一般来说,张量可以具有任意长度,取决于机器的内存限制。
可以通过张量的索引来访问任一元素。如x[3]
可以通过调用Python的内置len()函数来 访问张量的长度。如len(x)
当用张量表示一个向量(只有一个轴)时,我们也可以通过.shape属性访问向量的长度
向量或轴的维度被用来表示向量或轴的长度,即向量或轴的元素数量。
然而,张量的维度用来表示张量具有的轴数。
矩阵,我们通常用粗体、大写字母来表示 (例如,、和), 在代码中表示为具有两个轴的张量。
当调用函数来实例化张量时, 我们可以[通过指定两个分量 和 来创建一个形状为 × 的矩阵]。
A = torch.arange(20).reshape(5, 4)
A
"""
tensor([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15],
[16, 17, 18, 19]])
"""
在代码中访问矩阵的转置
A.T
"""
tensor([[1, 2, 3],
[2, 0, 4],
[3, 4, 5]])
"""
张量(本小节中的“张量”指代数对象)是描述具有任意数量轴的 维数组的通用方法。
张量用特殊字体的大写字母表示(例如, 、 和 )。
代码实现三阶张量
X = torch.arange(24).reshape(2, 3, 4)
X
"""
tensor([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]],
[[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]]])
"""
标量、向量、矩阵和任意数量轴的张量(本小节中的“张量”指代数对象)有一些实用的属性。 例如,从按元素操作的定义中可以注意到,任何按元素的一元运算都不会改变其操作数的形状。 同样,[给定具有相同形状的任意两个张量,任何按元素二元运算的结果都将是相同形状的张量]。 例如,将两个相同形状的矩阵相加,会在这两个矩阵上执行元素加法。
A = torch.arange(20, dtype=torch.float32).reshape(5, 4)
B = A.clone() # 通过分配新内存,将A的一个副本分配给B
A, A + B
"""
(tensor([[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.],
[12., 13., 14., 15.],
[16., 17., 18., 19.]]),
tensor([[ 0., 2., 4., 6.],
[ 8., 10., 12., 14.],
[16., 18., 20., 22.],
[24., 26., 28., 30.],
[32., 34., 36., 38.]]))
"""
两个矩阵的按元素乘法称为Hadamard积(Hadamard product)(数学符号 ⊙ )
A * B
"""
tensor([[ 0., 1., 4., 9.],
[ 16., 25., 36., 49.],
[ 64., 81., 100., 121.],
[144., 169., 196., 225.],
[256., 289., 324., 361.]])
"""
将张量乘以或加上一个标量不会改变张量的形状,其中张量的每个元素都将与标量相加或相乘。
a = 2
X = torch.arange(24).reshape(2, 3, 4)
a + X, (a * X).shape
"""
(tensor([[[ 2, 3, 4, 5],
[ 6, 7, 8, 9],
[10, 11, 12, 13]],
[[14, 15, 16, 17],
[18, 19, 20, 21],
[22, 23, 24, 25]]]),
torch.Size([2, 3, 4]))
"""
计算任意张量元素的和
x = torch.arange(4, dtype=torch.float32)
x, x.sum()
"""
(tensor([0., 1., 2., 3.]), tensor(6.))
"""
A.shape, A.sum()
"""
(torch.Size([5, 4]), tensor(190.))
"""
默认情况下,调用求和函数会沿所有的轴降低张量的维度,使它变为一个标量
我们还可以[ 指定张量沿哪一个轴来通过求和降低维度]
以矩阵为例,为了通过求和所有行的元素来降维(轴0),可以在调用函数时指定axis=0。 由于输入矩阵沿0轴降维以生成输出向量,因此输入轴0的维数在输出形状中消失。
A_sum_axis0 = A.sum(axis=0)
A_sum_axis0, A_sum_axis0.shape
"""
(tensor([40., 45., 50., 55.]), torch.Size([4]))
"""
指定axis=1将通过汇总所有列的元素降维(轴1)。因此,输入轴1的维数在输出形状中消失。
A_sum_axis1 = A.sum(axis=1)
A_sum_axis1, A_sum_axis1.shape
"""
(tensor([ 6., 22., 38., 54., 70.]), torch.Size([5]))
"""
沿着行和列对矩阵求和,等价于对矩阵的所有元素进行求和。
A.sum(axis=[0, 1]) # 结果和A.sum()相同
"""
tensor(190.)
"""
[一个与求和相关的量是平均值(mean或average)]。 我们通过将总和除以元素总数来计算平均值。 在代码中,我们可以调用函数来计算任意形状张量的平均值。
A.mean(), A.sum() / A.numel(),A
"""
(tensor(9.5000), tensor(9.5000))
"""
同样,计算平均值的函数也可以沿指定轴降低张量的维度。
A.mean(axis=0), A.sum(axis=0) / A.shape[0]
"""
(tensor([ 8., 9., 10., 11.]), tensor([ 8., 9., 10., 11.]))
"""
计算总和或均值时保持轴数不变
torch.sum(input, list: dim, bool: keepdim=False, dtype=None) → Tensor
input:输入一个tensor
dim:要求和的维度,可以是一个列表
keepdim:求和之后这个dim的元素个数为1,所以要被去掉,如果要保留这个维度,则应当keepdim=True
sum_A = A.sum(axis=1, keepdims=True)
sum_A
"""
tensor([[ 6.],
[22.],
[38.],
[54.],
[70.]])
"""
例如,由于sum_A在对每行进行求和后仍保持两个轴,我们可以(通过广播将A除以sum_A)。
A / sum_A
"""
tensor([[0.0000, 0.1667, 0.3333, 0.5000],
[0.1818, 0.2273, 0.2727, 0.3182],
[0.2105, 0.2368, 0.2632, 0.2895],
[0.2222, 0.2407, 0.2593, 0.2778],
[0.2286, 0.2429, 0.2571, 0.2714]])
"""
如果我们想沿[某个轴计算A元素的累积总和], 比如axis=0(按行计算),可以调用cumsum函数。 此函数不会沿任何轴降低输入张量的维度。
A.cumsum(axis=0)
"""
tensor([[ 0., 1., 2., 3.],
[ 4., 6., 8., 10.],
[12., 15., 18., 21.],
[24., 28., 32., 36.],
[40., 45., 50., 55.]])
"""
给定两个向量 , 它们的点积(dot product) (或 ⟨,⟩ ) 是相同位置的按元素乘积的和:。
y = torch.ones(4, dtype = torch.float32)
x, y, torch.dot(x, y)
"""
(tensor([0., 1., 2., 3.]), tensor([1., 1., 1., 1.]), tensor(6.))
"""
我们可以通过执行按元素乘法,然后进行求和来表示两个向量的点积
torch.sum(x * y)
"""
tensor(6.))
"""
在代码中使用张量表示矩阵-向量积,我们使用mv函数。 当我们为矩阵A和向量x调用torch.mv(A, x)时,会执行矩阵-向量积。 注意,A的列维数(沿轴1的长度)必须与x的维数(其长度)相同。
A, x, A.shape, x.shape, torch.mv(A, x)
"""
(tensor([[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.],
[12., 13., 14., 15.],
[16., 17., 18., 19.]]),
tensor([0., 1., 2., 3.]),
torch.Size([5, 4]),
torch.Size([4]),
tensor([ 14., 38., 62., 86., 110.]))
"""
我们可以将矩阵-矩阵乘法 看作简单地执行 次矩阵-向量积,并将结果拼接在一起,形成一个 × 矩阵
在下面的代码中,我们在A和B上执行矩阵乘法。 这里的A是一个5行4列的矩阵,B是一个4行3列的矩阵。 两者相乘后,我们得到了一个5行3列的矩阵。
B = torch.ones(4, 3)
A, B, torch.mm(A, B)
"""
(tensor([[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.],
[12., 13., 14., 15.],
[16., 17., 18., 19.]]),
tensor([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]]),
tensor([[ 6., 6., 6.],
[22., 22., 22.],
[38., 38., 38.],
[54., 54., 54.],
[70., 70., 70.]]))
"""
范数是向量元素平方和的平方根
在 范数中常常省略下标 2,也就是说 等同于
在代码中,我们可以按如下方式计算向量的 范数。
u = torch.tensor([3.0, -4.0])
torch.norm(u)
"""
tensor(5.)
"""
深度学习中更经常地使用 范数的平方,也会经常遇到 范数,它 表示为向量元素的绝对值之和:
与 范数相比, 范数受异常值的影响较小。 为了计算 范数,我们将绝对值函数和按元素求和组合起来。
torch.abs(u).sum()
"""
tensor(7.)
"""
范数和 范数都是更一般的 范数的特例:
类似于向量的 范数, [矩阵] (的Frobenius范数(Frobenius norm)是矩阵元素平方和的平方根:)
Frobenius范数满足向量范数的所有性质,它就像是矩阵形向量的 范数。 调用以下函数将计算矩阵的Frobenius范数。
torch.norm(torch.ones((4, 9)))
"""
tensor(6.)
"""
详细请参考教学文档 https://zh.d2l.ai/chapter_preliminaries/calculus.html
如果 的导数存在,这个极限被定义为
如果 ′() 存在,则称 在 处是可微(differentiable)的。 如果 在一个区间内的每个数上都是可微的,则此函数在此区间中是可微的
为了更好地解释导数,让我们做一个实验。 (定义 )如下:
%matplotlib inline
import numpy as np
from matplotlib_inline import backend_inline
from d2l import torch as d2l
def f(x):
return 3 * x ** 2 - 4 * x
通过令 =1 并让 ℎ 接近 0
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
"""
h=0.10000, numerical limit=2.30000
h=0.01000, numerical limit=2.03000
h=0.00100, numerical limit=2.00300
h=0.00010, numerical limit=2.00030
h=0.00001, numerical limit=2.00003
"""
设 是一个具有 个变量的函数,偏导数可以表示为
函数()相对于的梯度是一个包含个偏导数的向量:
,
其中 通常在没有歧义时被 取代。
假设可微分函数 有变量 ,其中每个可微分函数 都有变量 。 注意, 是 的函数。 对于任意 =1,2,…, ,链式法则给出: