0


【自用】动手学深度学习——跟李沐学AI要点

自用,是学习实时笔记,未条条记录,没有进一步加工组织语言,按需查看

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

本文转载自: https://blog.csdn.net/qq_73462547/article/details/141867901
版权归原作者 Fibre1213 所有, 如有侵权,请联系我们删除。

“【自用】动手学深度学习——跟李沐学AI要点”的评论:

还没有评论