动手学深度学习Pytorch---预备知识

【1】预备知识书籍

1.1 数据操作

1)x=torch.arange(12) #包含以0开始的前12个整数的行向量,默认为整数。也可指定创建类型为浮 点数。

2)x.shape #可通过张量的shape属性来访问张量(沿每个轴的长度)的形状。

3)x.numel() #返回数组中元素的个数

4)torch.Size([12]) #检测它的大小

5)X=x.reshape(3,4) #改变张量的形状而不改变元素数量和元素值。
#等价于x.reshape(-1,4)或x.reshape(3,-1)

6)#torch.zeros() #全0
#torch.ones() #全1

7)torch.randn(3,4) #每个元素都从均值为0、标准差为1的标准高斯分布(正太分布)中随机采样

8)#torch.cat((X,Y),dim=0) #将多个张量连结在一起,并给出沿哪个轴连结。

9)############广播机制
#大多数情况下,我们将沿着数组中长度为1的轴进行广播。将元素复制,不是填0。
#例:a=[[0],[1],[2]] b=[[0,1]] ,
#广播机制后:a=[[0,0],[1,1],[2,2]] b=[[0,1],[0,1],[0,1]]

10)#X+=Y #减少操作的内存开销

11)a=torch.tensor([3.5]) #要将大小为1的张量转换为python标量,我们可以调用item函数或python 的内置函数a.item(),float(a),int(a)

1.2 数据预处理:处理csv文件

import os
import pandas as pd
import torch

 1)创建一个人工数据集,并存储在csv(逗号分隔值)文件
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')

 2)读取csv(逗号分隔值)文件
data=pd.read_csv(data_file)
print(data)

3)“NaN”项代表缺失值。为了处理缺失的数据,典型的方法包括 插值法 和 删除法 ,其中插值法用一个替代值弥补缺失值,而删除法则直接忽略缺失值。这里,我们将考虑插值
inputs,outputs=data.iloc[:,0:2],data.iloc[:,2]#将data中第0、1列拿出来为inputs,第2列为outputs
inputs=inputs.fillna(inputs.mean())#将inputs中为NA的填充,此处填充为inputs的均值
print(inputs)

4)对于inputs中的类别值或离散值,我们将“NaN"视为一个类别
inputs=pd.get_dummies(inputs,dummy_na=True)#get_dummies:方法是为了将原本不好区分的数据进行再次打标签区分,从而得到更细的数据(类似one-hot编码)
#print(inputs)

5)现在inputs和outputs中所有条目都是数值类型,它们可以转换为张量格式。
X,y=torch.tensor(inputs.values),torch.tensor(outputs.values)

1.3 线性代数

1)计算总和或均值时保持轴数不变
A=torch.arange(40).reshape(2,5,4)
sumA=A.sum(axis=1,keepdim=True)

2)某个轴计算A元素的累积总和
A.cumsum(axis=0)

3)点积是相同位置的按元素乘积的和:torch.dot

4)矩阵向量积Ax是一个长为m的列向量,其i元素是点积ax:torch.mv(A,x)

5)矩阵A、B的乘法:torch.mm(A,B)

6)L1范数,表示为向量元素的绝对值之和:torch.abs(u).sum(); L2范数是向量元素平方和的平方根:torch.norm

7)矩阵的 弗罗贝尼乌斯范数(Frobenius norm)是矩阵元素的平方和的平方根:torch.norm(torch.ones(4,9))

1.4 线性回归+基础优化算法

一、线性回归

1)总结
1. 线性回归是对n维输入的加权,外加偏差。
2. 使用平方损失来衡量预测值和真实值的差异。
3. 线性回归有显示解。
4. 线性回归可以看做是单层神经网络。

二、基础优化方法

1)梯度下降
1. 挑选一个初始值 w 0 w_0 w0
2. 重复迭代参数t = 1,2,3 w t = w t − 1 − θ ∂ ℓ ∂ w t − 1 w_t = w_{t-1} - \theta {\partial \ell \over \partial w_{t-1}} wt=wt1θwt1
3. 沿梯度方向将增加损失函数值
4. 学习率:步长的超参数。(不能太小,也不能太大)
学 习 率 是 超 参 数 \textcolor{red}{学习率是超参数}

2)小批量随机梯度下降
1. 在整个训练集上算梯度太贵,我们可以随机采样b个样本 i 1 i_1 i1 i 2 i_2 i2、… i b i_b ib来近似损失
2. 1 b Σ ℓ ( X i , y i , w ) {1\over b}\Sigma\ell(X_i,y_i,w) b1ΣXi,yi,w
2. b是批量大小,另外一个重要的超参数。
b ( 批 量 大 小 ) 是 超 参 数 \textcolor{red}{b(批量大小)是超参数} b
4. 选择批量大小:(1)不能太小。每次计算量太小,不适合并行来最大利用计算资源。
(2)不能太大。内存消耗增加,浪费计算,例如如果所有样本都是相同的。

3)总结
1. 梯度下降通过不断沿着反梯度方向更新参数求解。
2. 小批量随机梯度下降是深度学习默认的求解算法。
3. 两个重要的超参数是批量大小和学习率。

三、线性回归的从零开始实现

我们将从零开始实现整个方法,包括数据流水线、模型、损失函数、和小批量随机梯度下降优化器。

import matplotlib.pyplot as plt
import torch
import random
from d2l import torch as d2l

根据带有噪声的线性模型构造一个人造数据集。我们使用线性模型参数
w = [ 2 , − 3.4 ] T w=[2,-3.4] ^T w=[2,3.4]T b = 4.2 b=4.2 b=4.2和噪声项 ϵ \epsilon ϵ生成数据集及其标签:
y = X w + b + ϵ y=Xw+b+\epsilon y=Xw+b+ϵ

def synthetic_data(w,b,num_examples):
    """生成 y = Xw + b + 噪声。"""
    X=torch.normal(0,1,(num_examples,len(w)))
    y=torch.matmul(X,w)+b
    #y加入噪声
    y+=torch.normal(0,0.01,y.shape)
    return X,y.reshape((-1,1))

true_w=torch.tensor([2,-3.4])
true_b=4.2
#生成特征和标签,即有了训练样本
features,labels=synthetic_data(true_w,true_b,1000)
######################
#第0个样本
print('features',features[0],'\nlabel',labels[0])
#图表示
d2l.set_figsize()
##detach(),是因为要从图中detach出来,不要再求梯度,才能转到numpy中。
d2l.plt.scatter(features[:,1].detach().numpy(),
                labels.detach().numpy(),1)
d2l.plt.show()
#######################

定义一个data_iter函数,该函数接收批量大小,特征矩阵和标签向量作为输入,生成大小为batch_size的小批量。(给我一些样品标号,每次随机从里面选取batch_size个样本返回出来。)

#batch_size:批量大小;features:特征;labels标签。
def data_iter(batch_size,features,labels):
    num_examples=len(features)
    indices=list(range(num_examples))
    #这些样本是随机读取的,没有特定的顺序。shuffle:打乱
    random.shuffle(indices)
    for i in range(0,num_examples,batch_size):
        batch_indices=torch.tensor(indices[i:min(i+
                        batch_size,num_examples)])
        yield features[batch_indices],labels[batch_indices]
##yield就是return返回一个值,并且记住这个返回的位置,下次迭代就从这个位置后开始。
############################
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)#随机初始化均值为0,方差为0.01的正太分布。
b=torch.zeros(1,requires_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):  #params中包含所有的w和b
    '''小批量随机梯度下降'''
    #不计算梯度,更新时不参与梯度计算
    with torch.no_grad():
        for param in params:
            param-=lr*param.grad/batch_size
            param.grad.zero_()

训练过程

lr=0.03#学习率
num_epochs=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)#X和y的小批量损失
        #因为l形状是(batch_size,1),而不是一个标量。l中的所有元素被加到一起
        #并以此计算关于[w,b]的梯度
        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().item())}')

比较真实参数和通过训练学到的参数来评估训练的成功程度

print(f'w的估计误差:{true_w-w.reshape(true_w.shape)}')
print(f'b的估计误差:{true_b-b}')

四、线性回归的简洁实现

import torch
import numpy as np
from torch.utils import data
from d2l import torch as d2l
from torch import ne, nn  #nn是神经网络的缩写

#通过使用深度学习框架来简洁地实现 线性回归模型 生成数据集
true_w=torch.tensor([2,-3.4])
true_b=4.2
features,labels=d2l.synthetic_data(true_w,true_b,1000)

def load_array(data_arrays,batch_size,is_train=True):
    '''构造一个pyTorch数据迭代器。'''
    #假设已经有features,labels可以做成一个list存到TensorDataset中,data_arrays->(features,labels)
    dataset=data.TensorDataset(*data_arrays)
    return data.DataLoader(dataset,batch_size,shuffle=is_train)#随机挑选batch_size个样本出来

batch_size=10
data_iter=load_array((features,labels),batch_size)
#print(next(iter(data_iter)))

#使用框架的预定义好的层
net=nn.Sequential(nn.Linear(2,1))#2:输入维度,1:输出维度
#Sequential:容器。将层按顺序放在一起

#初始化模型参数
net[0].weight.data.normal_(0,0.01)#net[0]即Sequential中的第0层
net[0].bias.data.fill_(0)

#计算均方误差使用的是MSELoss类,也称为平方L2范数
loss=nn.MSELoss()

#实例化SGD实例
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(features),labels)
    print(f'epoch {epoch+1},loss{l:f}')

四、线性回归QA
1)不管是gd(梯度下降)还是sgd怎么找到合适的学习率?
答:1. 用对学习率不那么敏感的算法,如Adam。2.通过合理的参数初始化。3. 有找学习率方法(后面)。
2)batch_size是否会最终影响模型结果?
答:小可以,对收敛好。大不行。噪音对网络会更鲁棒,泛化性更好。
3)训练过程中,过拟合和欠拟合情况下,学习率和批次该如何进行调整?
答:学习率和批次一般不影响收敛。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值