【自用】动手学深度学习——跟李沐学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 + YX += 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

inputsoutputs中的所有条目都是数值类型,它们可以转换为张量格式。

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]')



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。