【自用】动手学深度学习——跟李沐学AI要点
Fibre1213 2024-09-14 09:31:01 阅读 90
自用,是学习实时笔记,未条条记录,没有进一步加工组织语言,按需查看
04数据操作+数据预处理
代码:d2l-zh/pytorch/chapter_preliminaries/index.ipynb
N维数组是机器学习和神经网络的主要数据结构
创造数组:形状,数据类型,值
访问元素的切片区间注意:[1:3,]开区间不包括3;[::3,::2]跳着访问,每三行
、每两列访问一个元素
ctrl回车单行运行
import torch
张量(n维数组)表示一个数值组成的数组 可多维度 torch.arange()
x.shape 形状 x.numel()张量元素总数 x.reshape(,)不改变数量和元素量
torch.zeros((2,3,4)),torch.ones((2,3,4))
python列表赋值torch.tensor(数组)
按元素运算符
<code>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 # **运算符是求幂运算
把多个张量连结,拼接
dim=0行,dim=1列
广播机制,维度不一样数组,赋值多余维度再运算
X[-1],最后一行X[1:3]1-2行
=赋值
节省内存
Y=X+Y产生新的内存
原地执行
可以使用切片表示法将操作的结果分配给先前分配的数组
Y[:] = <expression>
如果在后续计算中没有重复使用
X
, 我们也可以使用X[:] = X + Y
或X += Y
来减少操作的内存开销。
NumPy张量
A = X.numpy()
B = torch.tensor(A)
type(A), type(B)
(numpy.ndarray, torch.Tensor)
要(将大小为1的张量转换为Python标量),我们可以调用
item
函数或Python的内置函数。
a = torch.tensor([3.5])
a, a.item(), float(a), int(a)
(tensor([3.5000]), 3.5, 3.5, 3)
数据预处理
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')
我们导入`pandas`包并调用`read_csv`函数。该数据集有四行三列。其中每行描述了房间数量(“NumRooms”)、巷子类型(“Alley”)和房屋价格(“Price”)。
import pandas as pd
data = pd.read_csv(data_file)
print(data)
处理缺失数据
插值法用一个替代值弥补缺失值,而删除法则直接忽略缺失值。
inputs, outputs = data.iloc[:, 0:2], data.iloc[:, 2]
inputs = inputs.fillna(inputs.mean()) #插值法,均值
print(inputs)
对于
nputs
中的类别值或离散值,我们将“NaN”视为一个类别。非数值变成数值。
NumRooms Alley
0 3.0 Pave
1 2.0 NaN
2 4.0 NaN
3 3.0 NaN
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
inputs
和outputs
中的所有条目都是数值类型,它们可以转换为张量格式。
import torch
X = torch.tensor(inputs.to_numpy(dtype=float))
y = torch.tensor(outputs.to_numpy(dtype=float))
X, y
QA:
1.可以参考这个网页的第一个回答:https://stackoverflow.com/questions/49643225/whats-the-difference-between-reshape-and-view-in-pytorch
view只能作用在连续的张量上(张量中元素的内存地址是连续的)。而reshape连续or非连续都可以。调用x.reshape的时候,如果x在内存中是连续的,那么x.reshape会返回一个view(原地修改,此时内存地址不变),否则就会返回一个新的张量(这时候内存地址变了)。所以推荐的做法是,想要原地修改就直接view,否则就先clone()再改。
05 线性代数
p1线性代数的一些概念
p2p3
x = torch.arange(4)
一维张量
A = torch.arange(20).reshape(5, 4)
矩阵
A.T
矩阵的转置
B = A.clone() # 通过分配新内存,将A的一个副本分配给B
两个矩阵的按元素乘法称为Hadamard积(Hadamard product)(数学符号)
A_sum_axis0 = A.sum(axis=0) 输入轴0的维数在输出形状中消失
A.sum(axis=[0, 1]) 两个维度求和,sum维度是最后一个维度
A.mean()均值
A.mean(axis=0)按照维度求均值
不丢掉维度,而是把他变成1
sum_A = A.sum(axis=1, keepdims=True)
sum_A = A.sum(axis=1, keepdims=True)
sum_A2 = A.sum(axis=1)
sum_A,A,sum_A2
(tensor([[ 6.],
[22.],
[38.],
[54.],
[70.]]),
tensor([[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.],
[12., 13., 14., 15.],
[16., 17., 18., 19.]]),
tensor([ 6., 22., 38., 54., 70.]))
如果我们想沿[某个轴计算A元素的累积总和], 比如axis=0(按行计算),可以调用cumsum函数。如果我们想沿[某个轴计算A元素的累积总和], 比如axis=0(按行计算),可以调用cumsum函数。
A.cumsum(axis=0)
B=A.cumsum(axis=0)
C=A.sum(axis=0)
B,A,C
结果(tensor([[ 0., 1., 2., 3.],
[ 4., 6., 8., 10.],
[12., 15., 18., 21.],
[24., 28., 32., 36.],
[40., 45., 50., 55.]]),
tensor([[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.],
[12., 13., 14., 15.],
[16., 17., 18., 19.]]),
tensor([40., 45., 50., 55.]))
[点积是相同位置的按元素乘积的和]
y = torch.ones(4, dtype = torch.float32)
x, y, torch.dot(x, y)
等价为torch.sum(x * y)
点积
矩阵-向量积,mv函数
A.shape, x.shape, torch.mv(A, x)
矩阵乘法mm
torch.mm(A, B)
范数 向量的范数是表示一个向量有多大。 这里考虑的大小(size)概念不涉及维度,而是分量的大小。
L2-
u = torch.tensor([3.0, -4.0])
torch.norm(u)
L1-绝对值求和
torch.abs(u).sum()
矩阵范数-Frobenius范数
torch.norm(torch.ones((4, 9)))
06 矩阵计算
标量导数
亚导数--不可微点
梯度:
y标量x列向量--变成一个行向量,第i个元素是y关于xi的导数
<u,v>表示内积
y列向量x标量--列向量,第i个元素是yi关于x的导数
分子布局符号,如果以上结果行列反过来,是分母布局
y,x均为列向量--得到矩阵,i行j列是yi与xj
扩展到矩阵求导
矩阵和标量:矩阵在下面--维度转置,矩阵在上面--维度不变
矩阵和向量:矩阵在下面--维度转置,前面加向量维度,矩阵在上面--维度不变,后面加
矩阵和矩阵:前面两项是上面,后面是转置下面
07 自动求导
向量链式法则
自动求导,计算一个函数在指定数的值,有别于符号求导和数值求导
计算图-等价于链式过程
代码分解成操作子,计算表示成无环的图,像树,显示构造,隐式构造
正向,从x到y,计算复杂度n,内存复杂度1;反向,从y到x,计算复杂度n,内存复杂度n
实现1:
import torch
x = torch.arange(4.0)
x.requires_grad_(True) # 等价于x=torch.arange(4.0,requires_grad=True)
x.grad # 默认值是None,存梯度的地方
y = 2 * torch.dot(x, x)
y.backward() #求导
x.grad
x.grad == 4 * x
实现2:
# 在默认情况下,PyTorch会累积梯度,我们需要清除之前的值
x.grad.zero_()
y = x.sum()
y.backward()
x.grad
# 对非标量调用backward需要传入一个gradient参数,该参数指定微分函数关于self的梯度。
# 本例只想求偏导数的和,所以传递一个1的梯度是合适的,大部分是标量对向量
x.grad.zero_()
y = x * x
# 等价于y.backward(torch.ones(len(x)))
y.sum().backward()
x.grad
将某些计算移动到记录的计算图之外
x.grad.zero_()
y = x * x
u = y.detach() #这里只赋值,u是常数,固定参数用
z = u * x
z.sum().backward()
x.grad == u
x.grad.zero_()
y.sum().backward()
x.grad == 2 * x
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
这就是隐式构造
08 线性回归 + 基础优化算法
p1线性回归,权重,偏差
线性模型可看作单层神经网络
衡量预估质量--平方损失
训练数据,收集数据决定权重和偏差,训练数据,越多越好,训练样本
参数学习,最小化训练损失
显式解
是相对于隐式解而言的,指的是在方程中,解可以明确地用自变量表示出来的形式。例如,如果方程的解可以写成 y=f(x)y=f(x) 的形式,那么这个解就是显式的。显式解的最大特点是能够直接用自变量 xx 表达出因变量 yy,而不需要通过其他方式求解。
显式解与隐式解的区别
显式解:可以直接用自变量表示因变量,例如 y=x2+1y=x2+1。
隐式解:无法直接用自变量表示因变量,例如 x2+y2=1x2+y2=1(这里无法直接从 x推导出 y 的表达式)。
p2
基础优化方法,不必知道显式解
剃度下降,沿负梯度方向,学习率是步长的超参数
小批量随机梯度下降
p3线性回归的从零开始实现
<code>%matplotlib inline
import random
import torch
from d2l import torch as d2l
#数据集
def synthetic_data(w,b,num):
X=torch.normal(0,1,(num,len(w)))#均值 方差 大小(行,列)
y=torch.matmul(X,w)+b
y+=torch.normal(0,0.01,y.shape)
return X,y.reshape((-1,1))#列向量返回 -1表示自动计算,1表示固定
ture_w=torch.tensor([2,-3.4])
ture_b=4.2
features,labels=synthetic_data(ture_w,ture_b,1000)
def data_iter(batch_size,features,labels):
num_examples=len(features)
indices=list(range(num_examples))
random.shuffle(indices)#打乱
#起始 结束+1 步幅
for i in range(0,num_examples,batch_size):
batch_indices=torch.tensor(indices[i:min(i+batch_size,num_examples)])
yield festures[batch_indices],labels[batch_indices]
batch_size=10
#for X,y in data_iter(batch_size,features,labels):
# print(X,'\n',y)
# break
定义初始化模型参数
w=torch.normal(0,0.01,size=(2,1),requires_grad=True)
b=torch.zeros(1,requested_grad=True)
定义模型
def linreg(X,w,b):
"""线性回归模型"""
return torch.matmul(X,w)+b
定义损失函数
def squared_loss(y_hat,y):
"""均方误差"""
return(y_hat-y.reshape(y_hat.shape))**2/2
定义优化算法
def sgd(params,lr,batch_size):
#参数 学习率 batch_size
"""小批量随机梯度下降"""
with torch.no_grad():
for param in params:
param -=lr*param.grad/batch_size
param.grad.zero_()
训练过程
lr=0.03
num_epochs=3#数据扫3遍
net=linreg
loss=squared_loss
for epoch in range(num_epochs):
for X,y in data_iter(batch_size,features,labels):
l=loss(net(X,w,b),y)
l.sum().backward()
sgd([w,b],,lr,batch_size)
with torch.no_grad():
train_l=loss(net(features,w,b),labels)
print(f'epoch{epoch+1},loss{float(train_l.mean()):f}')
p4简洁实现
import numpy as np
import torch
from torch.utils import data
from d2l import torch as d2l
ture_w=torch.tensor([2,-3.4])
ture_b=4.2
features,labels=d2l.synthetic_data(ture_w,ture_b,1000)
调用框架现有API读取数据
def load_array(data_arrays,batch_size,is_train=Ture):
"""构造一个PyTorch数据迭代器"""
dataset =data.TensorDataset(*data_arrays)
return data.DataLoader(dataset,batch_size,shuffle=is_train)#随机打乱
batch_size=10
data_iter=load_array((features,labels),batch_size)
next(iter(data_iter))
模型定义
from torch import nn
net=nn.Sequential(nn.Linear(2,1))
初始化参数
net[0].weight.data.normal_(0,0.01)
net[0].bias.data.fill_(0)
loss=nn.MSELoss()
trainer=torch.optim.SGD(net.parameters(),lr=0.03)
num_epochs=3
for epoch in range(num_epochs):
for X,y in data_iter:
l=loss(net(X),y)
trainer.zero_grad()
l.backward()
trainer.step()
l=loss(net(festures),labels)
print(f'epoch{epoch+1},loss[l:f]')
声明
本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。