自用,是学习实时笔记,未条条记录,没有进一步加工组织语言,按需查看
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(数组)
按元素运算符
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线性回归的从零开始实现
%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]')
版权归原作者 Fibre1213 所有, 如有侵权,请联系我们删除。