深度学习DeepLearning-基础知识

深度学习DeepLearning-基础知识

欢迎大家访问我的GitHub博客

https://lunan0320.cn

求单个样本的loss function是通过forward propagation

求梯度,即loss值关于参数w、b的偏导数,需要backward propagation

1.前言

与传统机器学习方法相比,深度学习的一个主要优势是可以处理不同长度的数据。

深度学习模型由神经网络错综复杂的交织在一起,包含层层数据转换

我们需要定义模型的优劣程度的度量,这个度量在大多数情况是**“可优化”的,我们称之为目标函数*(objective function)**

定义一个目标函数,并希望优化它到最低点。 因为越低越好,所以这些函数有时被称为损失函数(loss function,或cost function)

试图预测数值时,最常见的损失函数是平方误差(squared error)

通常将可用数据集分成两部分:训练数据集用于拟合模型参数,测试数据集用于评估拟合的模型。

优化算法:梯度下降(gradient descent)

在回归中,我们训练一个回归函数来输出一个数值; 而在分类中,我们训练一个分类器,它的输出即为预测的类别。

回归问题的常见的随时函数是平方差,分类问题的常见损失函数被称为交叉熵(cross-entropy)

学习预测不相互排斥的类别的问题称为多标签分类(multi-label classification)

搜索结果的排序也十分重要,我们的学习算法需要输出有序的元素子集

我们称这类数据中不含有“目标”的机器学习问题为无监督学习(unsupervised learning)

聚类(clustering)问题、主成分分析(principal component analysis)问题、因果关系(causality)和概率图模型(probabilistic graphical models)问题、生成对抗性网络(generative adversarial networks)

机器学习开发与环境交互并采取行动专注于*强化学习(reinforcement learning)

每个分类对应一个“动作”。 然后,我们可以创建一个环境,该环境给予agent的奖励。 这个奖励与原始监督学习问题的损失函数是一致的。

并不假设环境告诉agent每个观测的最优动作。 一般来说,agent只是得到一些奖励

当环境可被完全观察到时,我们将强化学习问题称为马尔可夫决策过程(markov decision process)

2.预备知识

2.1数据操作

张量类(在MXNet中为ndarray, 在PyTorch和TensorFlow中为Tensor)都与Numpy的ndarray类似

首先,GPU很好地支持加速计算,而NumPy仅支持CPU计算

其次,张量类支持自动微分

具有一个轴的张量对应数学上的向量(vector); 具有两个轴的张量对应数学上的矩阵(matrix)

import torch
x = torch.arange(12)#arange按序产生12个数字
x.shape #访问张量形状
x.numel()#知道张量元素总数
X = x.reshape(3, 4) #改变张量形状
torch.ones((2,3,4)) #初始化全为0或者全为1的张量
torch.zeros((1,2,3))
torch.randn(3,4)#每个元素都从均值为0、标准差为1的标准高斯分布(正态分布)中随机采样

x = torch.tensor([1.0,2,4,8]) #初始化数值
y = torch.tensor([2,2,2,2])
x+y, x*y, x/y,x**y
torch.exp(x) #对x这个tensor,求e的多少次
x = torch.arange(12, dtype = torch.float32).reshape(3,4)
y = torch.tensor([[2.0,3,4,5],[2,1,4,3],[6,1,3,4]])
#dim = 0表示按行拼接,dim = 1表示按列拼接
torch.cat((x,y),dim = 0), torch.cat((x,y),dim =  1)	
x.sum()#对张量中的所有元素求和
#广播机制
a = torch.arange(3).reshape(3,1) #a是3*1的矩阵
b = torch.arange(2).reshape(1,2) #b是1*2的矩阵
a+b   #a+b其实是无效的,但是a和b分别按列、行扩展为3*2的矩阵,然后相加是可以的
#索引和切片
x = torch.arange(12).reshape(3,4)
x[-1],x[1:3]
x[0:2,:] = 12 #修改第1、2行的所有数据为12,:表示所有的列元素

内存问题

通常情况下,我们希望原地执行这些更新。 其次,如果我们不原地更新,其他引用仍然会指向旧的内存位置, 这样我们的某些代码可能会无意中引用旧的参数。

可以使用X[:] = X + YX += Y来减少操作的内存开销。

转换为python对象

A = X.numpy()      #tensor可以直接转numpy
B = torch.tensor(A)#numpy也可以直接转tensor
type(A), type(B)
a = torch.tensor([3.5])
a.item() #将张量转换为python标量

2.2数据预处理

创建数据集

在Python中常用的数据分析工具中,我们通常使用pandas软件包。

#创建人工数据集
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,106000\n')
    f.write('4,NA,178100\n')
    f.write('NA,NA,140000\n')
#pandas读取数据
import os
import pandas as pd 

my_file = os.path.join('..','data','house_tiny.csv')
data = pd.read_csv(my_file)
print(data)
处理缺失值

插值法或者删除法,此处展示插值法

inputs, output = data.iloc[:,0:2],data.iloc[:,2]#此处iloc不需要()
print(inputs)
inputs = inputs.fillna(inputs.mean()) #用inputs中每一列的均值来替换NA
print(inputs)
inputs = pd.get_dummies(inputs,dummy_na = True) #对于离散型,或者类别值,存在则设置1,否则设置nan为0,类似ont-hot编吗
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
'''
转换为张量类型
import torch 
#直接对pandas数据用values属性取值
x,y = torch.tensor(inputs.values),torch.tensor(outputs.values)
x,y

2.3线性代数

标量

实例化两个标量

import torch
x = torch.tensor(3.0)
y = torch.tensor(2.0)
x+y,x*y
向量

标量是向量的元素或者分量

列向量是向量的默认方向

通过张量的索引来访问向量的任意元素

x = torch.arange(4)
x[3]

直接可以用python 的内置len()函数来访问张量的长度

len(x)

或者当向量是由一维张量组成时,可以用shape来访问向量的长度

x.shape
矩阵
import torch
a = torch.arange(20).reshape(4,5)
a,a.T
张量属性

将张量乘以或加上一个标量不会改变张量的形状,其中张量的每个元素都将与标量相加或相乘。

a = 2
x = torch.arange(24).reshape(2,3,4)
x, a+x
降维

axis = 0表示在y轴上求和,降维到轴0

x = torch.arange(4,dtype = torch.float32)
x.shape,x.sum()
x = torch.arange(100,dtype = torch.float32).reshape(5,20)
x_axis0 = x.sum(axis = 0)
x_axis0, x_axis0.shape
//取平均
A.mean(), A.sum() / A.numel()
//按轴取平均
A.mean(axis=0), A.sum(axis=0) / A.shape[0]
点积

torch.dot(x,y)

x = torch.arange(4, dtype = torch.float32)
y = torch.ones(4, dtype = torch.float32)
x, y , torch.dot(x,y)
矩阵向量积
torch.mv(A,x)
矩阵矩阵乘法

torch.mm(x,y)

a = torch.arange(20).reshape(4,5)
b = torch.ones(5,4,dtype = torch.long)
torch.mm(a,b)
范数

L1和L2范数

L1 直接求和

L2平方求和再开方

torch.norm(x)

2.4微积分

2.5自动微分

import torch
#此处必须是float型,否则不能用梯度
#计算梯度,先要对其设置梯度属性为True
x = torch.arange(4.0,requires_grad = True)
#默认梯度是None,输出没有结果
x.grad
分离计算

y是关于x 的函数,z是关于x和y的函数,想对z求关于x的偏导,此时需要将y视为一个常数,不希望反向传播的时候从y流向x

此时可以使用detach()方法构建新的变量,从y中分离,这样求偏导的时候,就不会从y流向x

x.grad.zero_()
y = x * x
u = y.detach()
z = u * x
z.sum().backward()
x.grad

但是这个过程会记录y的计算结果,因此直接可以在y上调用反向传播,得到y关于x的导数

x.grad.zero_()
y.sum().backward()
x.grad

3.线性神经网络

3.1线性回归

常见回归问题:预测价格(房屋、股票等)、预测住院时间(针对住院病人等)、 预测需求(零售销量等)

给定一个数据集,我们的目标是寻找模型的权重w和偏置b, 使得根据模型做出的预测大体符合数据里的真实价格

损失函数(loss function)能够量化目标的实际值与预测值之间的差距。
l ( i ) ( w , b ) = 1 2 ( y ^ ( i ) − y ( i ) ) 2 . l^{(i)}(\mathbf{w}, b) = \frac{1}{2} \left(\hat{y}^{(i)} - y^{(i)}\right)^2. l(i)(w,b)=21(y^(i)y(i))2.
目标是找到一组参数,使得总的损失值最小:
w ∗ , b ∗ = argmin ⁡ w , b   L ( w , b ) . \mathbf{w}^*, b^* = \operatorname*{argmin}_{\mathbf{w}, b}\ L(\mathbf{w}, b). w,b=w,bargmin L(w,b).

随机梯度下降

通常会在每次需要计算更新的时候随机抽取一小批样本, 这种变体叫做小批量随机梯度下降

更难做到的是找到一组参数,这组参数能够在我们从未见过的数据上实现较低的损失, 这一挑战被称为泛化(generalization)

可以调整但不在训练过程中更新的参数称为超参数(hyperparameter)

调参(hyperparameter tuning)是选择超参数的过程

正态分布与平方损失

损失函数是平方误差的原因是:根据似然函数求出

对于给定的x观测特定的y的似然likehood:
P ( y ∣ x ) = 1 2 π σ 2 exp ⁡ ( − 1 2 σ 2 ( y − w ⊤ x − b ) 2 ) . P(y \mid \mathbf{x}) = \frac{1}{\sqrt{2 \pi \sigma^2}} \exp\left(-\frac{1}{2 \sigma^2} (y - \mathbf{w}^\top \mathbf{x} - b)^2\right). P(yx)=2πσ2 1exp(2σ21(ywxb)2).
根据极大似然估计法,参数w和b的最优值就是使得似然值最大的值:
P ( y ∣ X ) = ∏ i = 1 n p ( y ( i ) ∣ x ( i ) ) . P(\mathbf y \mid \mathbf X) = \prod_{i=1}^{n} p(y^{(i)}|\mathbf{x}^{(i)}). P(yX)=i=1np(y(i)x(i)).
因为优化一般都是找到一个最小值,因此,这里求最小化的负对数似然
− log ⁡ P ( y ∣ X ) -\log P(\mathbf y \mid \mathbf X) logP(yX)
即求:
− log ⁡ P ( y ∣ X ) = ∑ i = 1 n 1 2 log ⁡ ( 2 π σ 2 ) + 1 2 σ 2 ( y ( i ) − w ⊤ x ( i ) − b ) 2 . -\log P(\mathbf y \mid \mathbf X) = \sum_{i=1}^n \frac{1}{2} \log(2 \pi \sigma^2) + \frac{1}{2 \sigma^2} \left(y^{(i)} - \mathbf{w}^\top \mathbf{x}^{(i)} - b\right)^2. logP(yX)=i=1n21log(2πσ2)+2σ21(y(i)wx(i)b)2.

然而,前面的是与超参数 σ 有关的常数项,其余部分和前面介绍的均方误差是一样的。 然而,前面的是与超参数\sigma有关的常数项,其余部分和前面介绍的均方误差是一样的。 然而,前面的是与超参数σ有关的常数项,其余部分和前面介绍的均方误差是一样的。

最小化均方误差等价于对线性模型的极大似然估计

全连接层(fully-connected layer)或称为稠密层(dense layer):每个输入与每个输出都相连

indices = list(range(num_examples))  #生成num_examples个自然数的列表
random.shuffle(indices) #对生成的顺序的数字,打乱,即把indices列表中的数字打乱
yield features[batch_indices], labels[batch_indices] #返回一个迭代器,一个for循环不断返回generator
初始化模型参数

在w和b中引入梯度属性

w = torch.normal(0, 0.01, size=(2,1), requires_grad=True)
b = torch.zeros(1, requires_grad=True)
定义模型

此处是定义的经典的线性回归model,其中X是 n * 2的矩阵,w是2 * 1的向量,Xw是一个向量,b是一个标量,但是由于广播机制,b会分别加到向量的每个分量上

def linreg(X, w, b):  
    """线性回归模型"""
    return torch.matmul(X, w) + b
定义损失函数

这里要将真实值y的形状转换为预测值y_hat的形状

def squared_loss(y_hat,y):
    return (y_hat - y.reshape(y_hat.shape))**2 / 2
定义优化算法

抽取一个小批量batch_size,根据参数计算损失的梯度,不断更新参数

def sgd(params,lr, batch_size):
    with torch.no_grad():
        for param in params:
            #此处要除以batch_size,这是对loss求导时可以推得的
            param  -= lr * param.grad / batch_size
			#梯度用完后要清零
            param.grad.zero_()
训练

重复训练:
g ← ∂ ( w , b ) 1 ∣ B ∣ ∑ i ∈ B l ( x ( i ) , y ( i ) , w , b ) ( w , b ) ← ( w , b ) − η g \mathbf{g} \leftarrow \partial_{(\mathbf{w},b)} \frac{1}{|\mathcal{B}|} \sum_{i \in \mathcal{B}} l(\mathbf{x}^{(i)}, y^{(i)}, \mathbf{w}, b) \\ (\mathbf{w}, b) \leftarrow (\mathbf{w}, b) - \eta \mathbf{g} g(w,b)B1iBl(x(i),y(i),w,b)(w,b)(w,b)ηg
每个epoch,都用data_iter遍历数据集

num_epochs和学习率lr都是超参数

(超参数需要反复实验调整)

loss.sum().backward()

一个向量是不进行backward操作的,而sum()后,由于梯度为1,所以对结果不产生影响。反向传播算法一定要是一个标量才能进行计算。

3.3 线性回归的简洁实现

import numpy as np
import torch
from torch.utils import data
#生成数据集
true_w = torch.tensor([2,-3.4])
true_b = 4.2
def synthetic_data(w,b ,num_examples):
    X = torch.normal(0, 1, size=(num_examples,len(w)))
    y = torch.matmul(X, w) + b
    y += torch.normal(0,0.01,y.shape)
    return X, y.reshape(-1,1)
features,labels = synthetic_data(true_w,true_b,1000)
features.shape,labels.shape

#读取数据集
def load_array(datas,batch_size, is_train = True):
    dataset = data.TensorDataset(*datas)
    #此处返回的是一个data_loader对象
    return data.DataLoader(dataset,batch_size,shuffle = is_train)
batch_size = 10
data_iter = load_array((features,labels),batch_size)
#查看data_iter的方法:先转换位迭代器的格式,然后next()打印出第一项
next(iter(data_iter))
#这里打印的是两个tensor,一个是X,一个是y
'''
[tensor([[ 0.7882, -0.7068],
         [ 0.5081,  0.2577],
         [-0.5769,  0.1545],
         [-0.3271, -0.6080],
         [-0.2716, -1.4628],
         [-1.1530, -1.4643],
         [ 0.1635, -0.2018],
         [-0.0753, -1.1161],
         [ 3.4251,  0.1953],
         [ 0.3589, -0.9478]]),
 tensor([[ 8.1742],
         [ 4.3357],
         [ 2.5157],
         [ 5.6106],
         [ 8.6395],
         [ 6.8726],
         [ 5.2155],
         [ 7.8377],
         [10.3918],
         [ 8.1590]])]
 '''

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值