深度学习与神经网络学习

一.深度学习概述

1.深度学习简介

机器学习在处理图像和文本方面能力较弱

深度学习是基于人工智能网络,深度是指网络中使用多层,每层都通过非线性变换处理数据,并逐渐提取出更复杂,更抽象的特征

传统机器学习算法依赖人工设计特征,并进行特征提取;而深度学习方法不需要人工,而是依赖算法自动提取特征

深度学习通过模仿人脑的神经网络来处理和分析复杂的数据,从大量数据中自动提取复杂特征,这也是深度学习被看作黑盒子,可解释性差的原因

深度学习尤其擅长高维数据,如图像语音和文本

2.深度学习特点

1.多层非线性变化:深度学习模型由多个层次组成,每一层都应用非线性激活函数对输入数据进行变换。较低的层级通常捕捉到简单的特征(如边缘、颜色等),而更高的层级则可以识别更复杂的模式(如物体或面部识别)。

2.自动特征提取:与传统机器学习算法不同,深度学习能够自动从原始数据中学习到有用的特征,而不需要人工特征工程。这使得深度学习在许多领域中表现出色。

3.大数据和计算能力:深度学习模型通常需要大量的标注数据和强大的计算资源(如GPU)来进行训练。大数据和高性能计算使得深度学习在图像识别、自然语言处理等领域取得了显著突破。

4.可解释性差:深度学习模型内部的运作机制相对不透明,被称为"黑箱",这意味着理解模型为什么做出特定决策可能会比较困难。这对某些应用场景来说是一个挑战。

提升可解释性可以让前面卷积层的神经元尽可能多,后面的神经元尽可能少

3.常用的深度学习模型

卷积神经网络CNN:输入层,隐藏层(卷积层,池化层,全连接层),输出层

主要用于图像处理,使用卷积层来自动提取图像中的局部特征,并通过池化层减少参数数量,提高计算效率

循环神经网络RNN

适用于处理序列数据,自然语言处理,语音识别

RNN具有记忆功能,可以处理输入数据的时间依赖性,但标准RNN难以捕捉长期依赖关系

自编码器:

一种无监督学习模型,通常用于降维,特征学习或者异常检测

自编码器由编码器和解码器组成,编码器将输入压缩降维,解码器将低维表示重建原始输入

生成对抗网络GAN:

广泛用于图像生成,视频合成等领域

包含两个子网络,生成器和判别器,生成器负责创建看起来真实的假样本,而且判别器则试图区分真假样本

Transformer:

主要用于自然语言处理任务,尤其是机器翻译,文本生成等

采用自注意力机制,使它能够并行处理整个句子的信息,在机器翻译,文本摘要等任务中表现出色

序列数据是指后面的数据对前面有依赖,比如长文本

深度强化学习:

图神经网络:

4.应用场景

计算机视觉:图像分类,目标检测,面部识别,图像生成

自然语言处理:机器翻译,情感分析,文本生成,语音识别,聊天机器人

推荐系统:电影、音乐推荐,电商推荐,社交媒体推荐

多模态大模型:一个大模型能处理所有类型任务

5.PyTorch框架

是一个基于Python语言的深度学习框架,将数据封装成张量进行处理

提供了灵活且高效的工具,用于构建、训练和部署机器学习和深度学习模型

广泛应用于学术研究和工业界

pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple安装

PyTorch特点

类似NumPy的张量计算

自动微分系统

深度学习库

动态计算图

GPU加速(CUDA支持)

支持多种应用场景

跨平台支持

二.张量(Tensor)

PyTorch中张量就是元素为同一种数据类型的多维矩阵,在PyTorch中,张量以"类"的形式封装起来,对张量的一些运算、处理的方法被封装在类中

PyTorch张量与NumPy数组类似,但PyTorch的张量具有GPU加速的能力(通过CUDA),这使得深度学习模型能够高效地在GPU上运行

PyTorch提供了对张量的强大支持,可以进行高效的数值计算、矩阵操作、自动求导等

张量是PyTorch中的核心数据抽象,PyTorch支持各种张量子类型,一维张量称为向量

1.张量的基本创建方式

torch.tensor基于指定数据创建张量

torch.Tensor基于指定性状创建张量,小写能做的大写都能做,还能直接创建指定维度的张量,生成随机数

torch.IntTensor如果类型不匹配,会尝试自动转换类型

torch.ones(a,b)和torch.ones_like(data)创建全1张量

torch.zeros(a,b)和torch.zeros_like(data)创建全0张量

torch.full(size(a,b),fill_value=指定值)和torch.full_like(data,fill_value=指定值)创建全为指定值张量

前面的调用生成a行b列的张量,后面的调用生成和tensor类型的张量data维度一致的张量

torch.arange(a,b,c)和torch.linspace(a,b,c)创建线性张量

torch.arange(a,b,c)从a到b,逐个+c,包含a但不包含b

torch.linspace(a,b,c)从a到b,一共c个,包含a和b

torch.random.initial_seed()和torch.random.manual_seed()随机种子设置

torch.random.initial_seed()采用当前系统时间戳创建随机种子

torch.random.manual_seed(a)设置随机种子后每次生成结果都一样

torch.rand(size(a,b))/randn(size(a,b))创建随机浮点类型张量,a行b列

torch.rand(size(a,b))均匀分布

randn(size(a,b))正态分布

torch.randint(low,high,size(a,b))创建随机整数类型张量,a行b列

2.张量元素类型转换

data.type(torch.DounleTensor)

data.type(torch.int16)转为int类型张量

data.half()/double()/float()/short()/int()/long()

half()是float16类型

t1.dtype是指t1中元素数据类型,type(t1)是指张量类型

Tensor.numpy函数可以将张量转换为ndarry数组,但是共享内存,通过.copy()函数避免共享

from_numpy函数可以将ndarry数组转换为Tensor张量,但是共享内存,通过.copy() 函数避免共享

torch.tensor可以将ndarry数组转换为Tensor,默认不共享内存

对于只有一个元素的张量,使用item将值从张量中提取出来

3.张量运算

add()加,张量加一个值则该数值和张量中每个值运算,不会修改原来的数据,要修改数据使用add_()可以用+符号代替

sub()减

mul()乘,张量相乘使用点乘,要求两个张量维度一致,对应元素直接相乘

matmul()矩阵相乘,使用转置相乘,a的列数=b的行数,结果是a行b列,符号是@

div()除,除法会有小数形式

neg()取反

dot()只对一维张量有效

4.张量运算函数

data.sum(dim=0),dim=0按列求和,dim=1按行求和,不写则全求和

data.max()

data.min()

data.mean()

上面四个有dim参数,下面的没有

data.pow(a),每个数开a次方,符号是**,等同于data ** a

data.sqrt(),平方根

data.exp(),e的每个元素次幂

data.log()

data.log2()

data.log10()

5.张量索引操作

简单行列索引

获取第二行的数据data行,列,data1,:或者data1

列表索引

返回(0,1)和(1,2)两个位置的元素,dataa,b,c,d,返回的是第a+1行,第c+1列的数据,第一个数组是行索引集合,第二个数组书列索引集合

返回第0,1行的1,2列共四个元素,data \[ \[0,1 ],1,2 ]

范围索引

返回前三行的前两列,data:3,:2

第二行到最后一行,前两列的数据,data1:,:2

所有奇数行,偶数列,data1::2,::2

布尔索引

datatorch.tensor(True,True,False),:

第三列,大于五的行数据datadata\[:,2>5]

第二行,大于五的列数据data:,data\[1>5]

多维索引

获取0轴上的第一个数据data0,:,:

获取1轴上的第一个数据data:,0,:

获取2轴上的第一个数据data:,:,0

6.张量形状操作

data.shape,输出torch.Size(a,b)表示a行b列

data.shape0输出行数

data.shape1输出列数

data.shape-1输出最后一维的大小

data.reshape(a,b)转换成a行b列的张量

保证张量数据不变的前提下改变数据的维度,将其转换成指定的形状

squeze()

删除形状为1的维度(降维)

unsqueeze(a)

在a轴上增加一个1维度

teamspose(a,b)

一次交换两个维度,不会改变原数据

permute(2,0,1)

一次交换多个维度,将012维度改变顺序为2,0,1维度顺序

view(a,b)

只能修改连续的张量,存储数据和逻辑顺序一致,修改后仍然连续

如果张量使用transpose或者permute修改后则不能用view

contigous()

把不连续的张量变为连续的张量,修改内存存储顺序

is_contigous()

判断张量是否连续

7.张量拼接操作

torch.cat(data1,data2,dim=0)函数可以将多个张量根据指定的维度拼接起来,不改变维度数,除了拼接的维度外,其他维度数必须保持一致

上述表示 在0维度上拼接两个张量

torch.stack(data1,data2,dim=0)函数在一个新的维度上连接一系列张量,会增加新维度,并且所有输入张量的形状必须完全相同,生成的是(2,原数据维度)维张量

8.自动微分模块

参数会根据损失函数关于对应参数的梯度进行调整,为了计算这些梯度,PyTorch内置了torch.autograd的微分模块,支持任意计算图的自动梯度计算

对损失函数求导,结合反向传播,更新权重参数w,b

多元线性公式y=wx+b

权重更新公式w新= w旧 - 学习率*梯度

偏置更新公式b新=b旧 - 学习率*梯度

实际开发中不考虑偏置

梯度基本计算:PyTorch不支持向量张量对向量张量的求导,只支持标量张量对向量张量的求导

如果x是张量,y必须是标量才可以求导

计算梯度:y.backward

获取x点的梯度值:x.grad

1.创建标量:

w = torch.tensor(10, requires_grad=True, dtype=torch.float),创建一个标量10,允许自动微分,浮点数类型

2.损失函数:

loss = 2 * w ** 2

3.计算梯度:

loss.sum().backward(),保证loss是一个标量

4.更新权重:

w.data = w.data - 0.01* w.grad

9.自动微分小技巧

一个张量一旦设置了自动微分,就不能直接转成numpy的ndarray对象了,需要通过detach()函数解决

t1如果设置了 requires_grad=True,则t1.numpy()报错

可以通过t2= t1.detach().numpy()拷贝另一份数据转换

三.线性回归

1.准备数据集

生成的值是numpy对象,需要转成张量形式,coef为权重w

首先创建数据集对象,把tensor转换成数据集对象

dataset = TensorDataset(x,y)

然后创建数据加载器对象

daraloader = DataLoader(daraset,batch_size = 16, shuffle = True),参数分别表示数据集对象, 批次大小,是否打乱数据(训练集打乱,测试集不打乱)

2.构建模型

下一步创建初始的线性回归模型

model= nn.Linear(1,1),参数表示输入的特征维度和输出特征维度

3.设置损失函数和优化器

创建损失对象

criterion = nn.MSELoss()

创建优化器对象

optimizer = optim.SGD(model.parameters(),lr = 0.01),参数分别表示模型参数和学习率

4.训练模型

epochs为训练轮数

epoch_loss为每轮的损失

total_loss总损失

train_sample为训练样本

按照训练轮数循环

for epoch in range(epochs)

从数据加载器中逐个批次获取数据

for train_x, train_y in dataloader

模型预测

y_pred = model(train_x)

计算损失

loss = criterion(y_pred, train_y.reshape(-1,1))

计算总损失

total_loss += loss.item()

total_sample += 1

梯度清零,反向传播,梯度更新

optimizer.zero_grad()

loss.backwart()

optimizer.step()

把本轮平均损失添加到列表中

loss_list.append(total_loss/total_sample)

绘制损失曲线

plt.plot(range(epochs),loss_list)

plt.title("损失值曲线变化图")

plt.grid()

绘制样本点分布情况

plt.scatter(x,y)

绘制训练模型的预测值

y_pred = torch.tensor(data = v \* model.weight + model.bias for v in x)

计算真实值

y_true = torch.tensor(data = v \* coeft + 14.5 for v in x)

绘制预测值和真实值的折线图

plt.plot(x,y_pred, color = 'red' , label = '预测值')

plt.plot(x, y_true , color = 'green', label = '真实值')

plt.legend()

plt.grid()

plt.show()

四.神经网络

1.神经网络概述

人工神经网络ANN也称神经网络,是一种模仿生物神经网络结构和功能的计算模型,人脑可以看作是一个生物神经网络,由众多的神经元连接而成,各个神经元传递复杂的电信号,树突接收到姝蕊你好,对信号处理,通过轴突输出信号,当电信号通过树突进入到细胞核时,会逐渐聚集电荷,达到一定的点位后,细胞会被激活,通过轴突发出电信号

神经网络由多个神经元组成,构建神经网络就是在构建神经元,来源不同树突的信息,进行加权计算,输入到细胞核中求和,再通过激活函数输出细胞值

神经网络优点:精度高,性能优于其他的机器学习方法,甚至在某些领域超过了人类

可以近似任意的非线性函数

近年来在学界和业界收到了热捧,有大量的框架和库可供调用

缺点:黑线,很难解释模型工作原理

训练时间长,需要大量算力

网络结构复杂,需要调整超参数

小数据集上表现不佳,容易发生过拟合

2.神经网络构建

有几个特征输入层就有几个神经元,相邻层神经元相互连接,同层神经元相互隔离

前层输出就是后层输入

全神经网络连接就是全连接,接收的样本数据是二维的

每个连接都有权重值

首先对特征加权求和,再传给激活函数处理

1.输入层:即输入x的那一层,每个输入特征对应一个神经元,输入层将数据传递给下一层的神经元

2.输出层:即输出y的那一层,输出层的神经元根据网络的任务(回归,分类等)生成最终的预测结果

3.隐藏层:输入层和输出层之间都是隐藏层,神经网络(),隐藏层的神经元通过加权和激活函数处理输入,并将结果传递到下一层。

每个神经元有内部状态值,激活值,内部状态值梯度和激活值梯度

每个神经元工作时,前向传播会产生两个值,内部状态值和激活值,反向传播时会产生激活值梯度和内部状态值梯度

内部状态值:神经元或隐藏单元的内部存储值,它反映了当前神经元接收到的输入、历史信息以及网络内部的权重计算结果

激活值:

四.激活函数

激活函数用于对每层的输出数据进行变换,进而为整个网络注入了非线性因素,此时,神经网络就可以拟合各种曲线

1.没有引入非线性因素的网络等价于使用一个线性模型来拟合

2.通过给网络输出增加激活函数,实现引入非线性因素,是的网络模型可以逼近任意函数,提升网络对复杂问题的拟合能力

1.sigmoid激活函数

激活函数公式:

x越大,整体越大,x为加权求和结果

sigmoid函数可以将任意的输入映射到(0,1)之间,当输入的值大致在小于-6或者大于6时,意味着输入任何值得到的激活值都是差不多的,这样会丢失部分的信息,比如输入100和输入10000经过sigmoid的激活值几乎都是等于1的,但是输入的数据之间相差100倍的信息就丢失了

对于sigmoid来说,输入值在-6,6之间,输出值才会有明显差异,输入值在-3,3之间才会有比较好的效果

通过上述导数图像,我们发现导数值范围时(0,0.25),当输入小于-6或者大于6时,sigmoid激活函数图像的导数接近为0,此时网络参数将更新极其缓慢,或者无法更新

一般来说,sigmoid网络在五层以内就会产生梯度消失现象,而且,该激活函数并不是以0为中心的,所以在实践中这种激活函数使用的很少,一般只用于二分类的输出层

2.tanh激活函数

x越大,整体越接近1,x越小,整体越接近-1

tanh在-3,3有效果,在-1,1效果明显,将值映射到-1,1,导数值范围在0,1

Tanh 函数将输入映射到 (−1,1)之间,图像以 0 为中心,在 0 点对称,当输入大概 <−3 或者 >3 时将被映射为 −1 或者 1。其导数值范围 (0,1),当输入的值大概 <−3 或者 >3 时,其导数近似 0。

与Sigmoid相比,它是以0为中心的,且梯度相对于sigmoid大,使得其收敛速度要比Sigmoid快,减少迭代次数,然而,从图中可以看出Tanh两侧的导数也为0,同样会造成梯度消失

若使用时可在隐藏层使用tanh函数,在输出层sigmoid函数

3.ReLU激活函数

默认情况下,ReLU只考虑正样本

ReLU激活函数将小于0的值映射为0,而大于0的值保持不变,它更重视正信号,而忽略负信号,这种激活函数运算更为简单,能够提高模型的训练效率

当x<0时,ReLU导数为0,当x>0时,则不存在饱和问题。所以ReLU能够在x>0时能保持梯度不衰减,从而缓解梯度消失问题,然而随着训练的推进,部分输入会落于小于0区域,导致对应权重无法更新。这种现象被称为"神经元死亡"

ReLU是目前最常用的激活函数,与sigmoid相比,ReLU的优势是:采用sigmoid函数,计算量大,反向传播求误差梯度时,计算量相对大,而采用ReLU激活函数,整个过程的计算量节省很多。sigmoid函数反向传播时,很容易就会出现梯度消失的情况,从而无法完成深层网格的训练。ReLU会使一部分神经元输出为0,这样就造成了网络的稀疏性,并且减少了参数的相互依存关系,缓解了过拟合问题的发生

4.softmax激活函数

softmax用于多分类过程中,它是二分类函数sigmoid在多分类上的推广,目的是将多分类的结果以概率的形式展现出来。计算方法如下:

softmax就是将网络输出的logits通过softmax函数,就映射成为(0,1)的值,而这些值的累和为1(满足概率的性质),那么我们将它理解成概率,选取概率最大(也就是值对应最大的)节点,作为我们的预测目标类别。

5.激活函数的选择方法

对于隐藏层:

1.优先选择ReLU激活函数

2.如果ReLU效果不好,那么尝试其他函数,如Leaky ReLU等

3.如果你使用了ReLU,需要注意一下Dead ReLU问题,避免出现0梯度从而导致过多的神经元死亡

4.少使用sigmoid激活函数,可以尝试使用tanh激活函数

对于输出层:

1.二分类问题选择sigmoid激活函数

2.多分类问题选择softmax激活函数

3.回归问题选择identity激活函数

五.参数初始化

在构建网络后,网络中的参数是需要初始化的,我们需要初始化的参数主要有权重和偏置,偏置一般初始化为0即可,而对权重的初始化则会更加重要

参数初始化的作用:1.防止梯度消失或爆炸:初始权重值过大或过小会导致梯度在反向传播中指数级增大或缩小

2.提高收敛速度:合理的初始化是的网络的激活值分布适中,有助于梯度高效更新

3.保持对称性破除:权重的初始化需要打破对称性,否则网络的学习能力会受到限制

1.常用的参数初始化方法

随机初始化

均匀分布初始化

权重参数初始化从区间均匀随机取值,默认区间为(0,1).可以设置为在均匀分布中生成当前神经元的权重,其中d为神经元的输入数量

正态分布初始化

随机初始化从均值为0,标准差是1的高斯分布中取样,使用一些很小的值对参数w进行初始化

优点:能有效打破对称性

缺点:随机选择范围不当可能导致梯度问题

使用场景:浅层网络或低复杂度模型。隐藏层1-3层,总层数不超过5层

全0初始化

所有权重初始化为0

优点:实现简单

缺点:无法打破对称性,所有神经元更新方向相同,无法有效训练

使用场景:几乎不使用,仅用于偏置项的初始化

全1初始化

所有权重初始化为1

优点:实现简单

缺点:无法打破对称性,所有神经元更新方向相同,无法有效训练

会导致激活值在网络中呈指数级增长,容易出现梯度爆炸

使用场景:测试或调试:比如验证神经网络是否能正常前向传播和反向传播

特殊模型结构:某些稀疏网络或特定的自定义网络中可能需要手动设置部分参数为1

偏置初始化:偶尔可以将偏置初始化为小的正值(0.1),但很少用1作为偏置的初始值

固定值初始化

所有权重初始化为固定值

优点:实现简单

缺点:无法打破对称性,所有神经元更新方向相同,无法有效训练

初始权重过大或过小可能导致梯度爆炸或梯度消失

使用场景:测试或调试

kaiming初始化

也叫HE初始化:HE初始化分为正态分布的HE初始化、均匀分布的HE初始化

正态分布的HE初始化:从0,std中抽取样本,std = sqrt(2/fan_in)

均匀分布的HE初始化:从-limit,limit中的均匀分布中抽取样本,limit是sqrt(6/fan_in)

fan_in为输入层神经元的个数,当前层接受的上一层的神经元的数量。简单来说,就是当前层接收多少个输入

一般使用ReLU激活函数

优点:适合ReLU,能保持梯度稳定

缺点:对非ReLU激活函数效果一般

使用场景:深度网络(10层及以上),使用ReLU,Leaky ReLU激活函数

xavier初始化

也叫Glorot初始化:分为正态分布的xavier初始化和均匀分布的xavier初始化

正态分布的xavier初始化:从0,std中抽取样本,std = sqrt(2/(fan_in+fan_out))

均匀分布的HE初始化:从-limit,limit中的均匀分布中抽取样本,limit是sqrt(6/(fan_in+fan_out))

fan_in为输入层神经元的个数,当前层接受的上一层的神经元的数量,fan_out为输出层神经元个数,当前层会传递给下一层的神经元的数量

优点:适用于Sigmoid,Tanh等激活函数,解决梯度消失问题

缺点:对ReLU等激活函数表现欠佳

使用场景:深度网络(10层及以上),使用Sigmoid或Tanh激活函数

六.神经网络搭建

在pytorch中定义深度神经网络其实就是层堆叠的过程,继承自nn.Module,实现两个方法:

_init_方法中定义网络中的层结构,主要是全连接层,并进行初始化

forward方法,在实例化模型的时候,底层会自动调用该函数。该函数中为初始化定义的layer传入数据,进行前向传播等。

七.损失函数

相关推荐
楼田莉子12 小时前
C++20现代特性:概念与约束
开发语言·c++·后端·学习·c++20
算法channel12 小时前
实测一个本地知识库:自动学习电脑里的几百个文件,一键导出总结报告!
学习
眼眸流转12 小时前
Dify学习笔记
笔记·学习·agent·dify
优秀的颜12 小时前
大模型基础
神经网络
一只QAQ12 小时前
c++小巧思
c++·笔记·学习
weixin_4684668512 小时前
PyTorch 与 TensorFlow 实战选型与应用场景指南
人工智能·pytorch·深度学习·算法·机器学习·tensorflow·深度学习框架
生成论实验室12 小时前
降U定律:宇宙认知动力学第一定律
人工智能·深度学习·语言模型·机器人·自动驾驶
Philtell12 小时前
漫谈学习之MapDiffusion算法学习
学习·mapdiffusion
yanxiaoyu11012 小时前
小白学习深度学习、强化学习的相关重要内容
人工智能·深度学习·学习