AI基础学习周报二

目录

摘要
Abstract
1、梯度下降算法
1.1 基本知识
1.2 学习率
2、反向传播算法
3、激活函数
3.1 基本概念
3.2 sigmoid函数
3.3 tanh函数
3.4 ReLU函数
4、PyTorch学习
4.1 PyTorch加载数据
4.2 TensorBoard使用
4.3 Transforms的使用
4.4 常见的transforms
4.5 torchvision中的数据集使用
4.6 Dataloader的使用
4.7 神经网络
总结

摘要

本周重点研究了梯度下降算法及其优化方法包括随机梯度下降与动量法、反向传播算法的计算图实现原理,以及常见激活函数如Sigmoid、Tanh和ReLU的特性与优劣。在PyTorch实践部分,系统学习了数据加载流程涉及Dataset与DataLoader、TensorBoard可视化工具、Transforms数据预处理方法如Resize、Normalize和RandomCrop,并完成了神经网络模块的构建与训练流程。通过理论推导与代码实践,深入理解了深度学习模型训练的核心组件及其在PyTorch框架中的实现机制。

Abstract

This week focused on the gradient descent algorithm and its optimizations including stochastic gradient descent with momentum, the computational graph implementation of backpropagation, and characteristics of activation functions such as Sigmoid, Tanh and ReLU. For PyTorch practice, key areas included data loading with Dataset and DataLoader, TensorBoard visualization, Transforms preprocessing covering Resize, Normalize and RandomCrop, and neural network construction. Theoretical analysis and code implementation provided insights into core components of deep learning training and their practical deployment in PyTorch.

1、梯度下降算法

1.1 基本知识

梯度下降法(Gradient descent,简称GD)是一阶最优化算法。 如下图所示,目标是找到一个b,使得损失函数最小
在这里插入图片描述
假设损失函数的二次函数如下图所示,可以找到损失函数值最小的地方。
在这里插入图片描述
换一种求解思路:随便给定一个b值,通过迭代优化的方式找到最好的值。如下图所示,当优化到最低点的时候斜率为零,b不会再被更新,就找到了最好的值。
在这里插入图片描述
以一个更加一般的形式表述,数据点有很多且函数是非线性时,如下图所示。
在这里插入图片描述
其中:学习率是人为设定的值,用来控制梯度下降的步长。
如下图所示,这个算法首先需要计算出所有样本的损失函数梯度,然后求平均值来更新参数。如果样本数量非常多,需要保存全部计算结构,内存开销需求大;如果计算很多数据才更新一次,收敛速度也会比较慢,如下图所示。
在这里插入图片描述
每次只用少部分数据更新可以改进上述问题,每次随机从n个样本里面选择m个样本,每次都不重复,这种改进方法被称为随机梯度下降,如下图所示。
在这里插入图片描述

  • 当样本方差较小的时候,使用少部分样本虽然会引入噪声,但是仍然可以按照正确的趋势来收敛函数
  • 随机梯度下降并非所有情况都是有效的,深度学习网络训练往往是一个非凸的优化过程,在参数空间里面分布着各种山脊和山谷,如下图所示。
    在这里插入图片描述

初始的网络参数会根据随机梯度下降,下一步会沿着切面的方向移动,以此类推,移动轨迹可能在山谷两侧来回震荡,难以收敛到更低的位置。
如果运动中加入一点阻尼,让运动更平滑一点,也许就会掉进山谷里。具体就是在下一次更新的时候不仅要计算新的梯度,还要保留上一次一部分的梯度,把两个方向加在一起,构成新的更新方向,如下图所示。
在这里插入图片描述
其中:保留的历史梯度称为动量。这个改进方法被称为使用动量的随机梯度下降。

1.2 学习率

一开始为了快速找到正确的收敛方向,会设置比较大的学习率。而随着训练过程,需要找到最好的结果,就不能盲目追求速度,要让网络更加细致的优化,防止损失函数剧烈震荡,所以需要设置一个初始值,然后每隔一段时间就降低学习率。如下图所示。
在这里插入图片描述
但是这种方法比较粗糙。可以通过梯度自动调整学习率,比如引入了新的变量r,r就是梯度大小随时间的积累量。如下介绍几种算法。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2、反向传播算法

在这里插入图片描述
根据上一节所讲的梯度下降算法,可以计算损失函数L对于w和b的梯度值,也就是偏导数,然后再沿着梯度的反方向,更新w和b就行。
在这里插入图片描述
为了更容易计算损失函数L对于w和b的偏导,最好先计算一个中间量,即L对y的偏导,这样L对w的偏导数就可以写成L对y的偏导乘以y对w对偏导,这种计算方法就是求导的链式法则。如下图所示,黄色部分从后向前计算参数梯度值的方法就是反向传播算法
在这里插入图片描述
当传播过程变难一些,过程如下图所示。
在这里插入图片描述
由单元运算和变量构成的计算流程图称为计算图,正向传播计算图如下图所示。
在这里插入图片描述
通过计算图来反向求出损失函数对于每个变量的梯度表达式。
在这里插入图片描述
在深度学习框架中,计算图中的元素的定义和使用非常便捷,比如乘法运算,在torch框架中就可以写成如下图右边代码的形式。其中forward函数以x和y为输入,输出就是二者的乘积,也就是向前传播的计算。在backward函数中,输入是grad_z就是损失函数L对z对偏导数,而grad_x和grad_y就是L对于x和y的偏导数,用链式法则求解即可,也就是反向传播的计算
在这里插入图片描述
在这里插入图片描述

3、激活函数

3.1 基本概念

给定一个线性变换,可以把x的值映射到一条直线上。如果再经过一次线性变换,也是一条直线。
在这里插入图片描述
也就是说,无论使用多少线性变换,或者叠加为神经网络,最终只能解决线性问题。为了能解决非线性问题,可以在线性单元后面加入非线性函数f,即激活函数。总之,激活函数的作用: 激活函数是用来加入非线性因素的,因为线性模型的表达能力不够,引入非线性函数作为激励函数,这样深层神经网络表达能力就更加强大(不再是输入的线性组合,而是几乎可以逼近任意函数)。
根据上一节的反向传播算法激活函数一定是连续可导函数,定义域是R,单调递增到s型曲线。
在这里插入图片描述

3.2 sigmoid函数

sigmoid函数图像如下所示。其中sigmoid函数的导数最大值是0.25。
在这里插入图片描述
当线性单元输出y的值非常大或者非常小的时候,可以看到sigmoid的函数的导数等于零,这种在正负无穷梯度为零的函数,称为饱和函数,而且无论如何取值,导数的最大值是0.25。这就意味着神经网络在反向传播的时候,每层梯度会被动缩小大约1/4。
在这里插入图片描述

如果网络层数很多或者某层出现极端的输出,反向传播的链式法则就会导致前几层的梯度几乎为零,参数不会被更新,下图的四层网络其实就等价为两层网络,这就是梯度消失现象
在这里插入图片描述
除此以外,sigmoid函数的取值是从0~1,始终大于零,这种函数称为非零均值函数
如果考虑一个神经元的输入是x1和x2,他们都是上一层sigmoid函数的输出,所以都是大于零的数。进行反向传播后得到w1和w2的梯度,下图中黄色字体的式子是始终大于零的,可以看到这两个参数的梯度正负完全取决于损失函数对o的导数,这就意味着w1和w2的梯度符号始终一致,被强制的同时正向或者反向更新,这样会使神经网络更慢的收敛到预定位置。
在这里插入图片描述

3.3 tanh函数

双曲正切函数的解析式函数图像和导数图像如下图所示,是一个零均值函数和饱和函数。
在这里插入图片描述

3.4 ReLU函数

为了解决梯度消失问题,提出了修正线性单元(ReLU函数),表达式函数图像和导数图像如下图所示。表达式函数是一个正比例映射,但是会抑制小于零的输入。只有当神经元输出大于零的时候才会回传梯度,小于零的时候就不会反向传播。
在这里插入图片描述

除此以外,ReLU函数在训练过程中,可以动态控制神经元的状态,要么激活大于零,要么等于零被抑制,这种性质为稀疏性。当然ReLU函数还存在归一化初始化等问题。

4、PyTorch学习

4.1 PyTorch加载数据

在这里插入图片描述

4.2 TensorBoard使用

4.2.1 SummaryWriter()

SummaryWriter 创建一个tensorboard文件, 文件保存在log_dir 目录(自己指定的目录)写文件,该文件可以被tensorboard解析。

参数:

  • log_dir: 保存目录位置。 默认值为 run/CURRENT_DATETIME_HOSTNAME ,每次运行后都会更改。使用分层文件夹结构可以轻松比较运行情况。 例如 为每个新实验传递“ runs / exp1”,“ runs / exp2”等,以便在它们之间进行比较。
  • flush_secs: 表示写入tensorboard文件的时间间隔
writer = SummaryWriter(log_dir='logs',flush_secs=60)

4.2.2 writer.add_scalar()

这个函数用于在tensorboard中加入loss,其中常用参数有:

  • tag:标签,如下所示的Train_loss
  • scalar_value:标签的值(y轴)
  • global_step:标签的x轴坐标
writer.add_scalar('Train_loss', loss, (epoch*epoch_size + iteration))

4.2.3 ensorboard --logdir=

在完成tensorboard的logs文件的生成后,可在命令行调用该文件,tensorboard网址。
在这里插入图片描述

具体代码如下(版本不同,命令会有差异):

tensorboard --logdir=logs
tensorboard --logdir="logs"
tensorboard --logdir "log"

也可指定端口名(一台服务器可能多个人在一起训练,同时使用一个端口可能冲突):

tensorboard --logdir=logs --port=6007

代码示例:

SummaryWriter 创建一个tensorboard文件, 文件保存在log_dir 目录写文件,该文件可以被tensorboard解析
参数:
log_dir:        保存目录位置。 默认值为 run/CURRENT_DATETIME_HOSTNAME ,每次运行后都会更改。
                使用分层文件夹结构可以轻松比较运行情况。 例如 为每个新实验传递“ runs / exp1”,“ runs / exp2”等,以便在它们之间进行比较。
flush_secs:     表示写入tensorboard文件的时间间隔
from torch.utils.tensorboard import SummaryWriter
writer = SummaryWriter("logs")            # 创建SummaryWriter() 类实例,将对应的事件文件存储到 logs 文件中

# writer.add_image()
add_scalar(): 将数添加到summary中
参数:
tag: 图标的标题
scalar_value:   需要保存的数值,对应y轴
global_step:    训练到多少步的时候对应的数值是多少,对应x轴


for i in range(100):
    writer.add_scalar("y = x", i, i)                       # 添加标量,即数

writer.close()

4.2.4 writer.add_graph()

这个函数用于在tensorboard中创建Graphs,Graphs中存放了网络结构,其中常用参数有:

  • model:pytorch模型
  • input_to_model:pytorch模型的输入

4.2.5 add_image()

绘制图片,可用于检查模型的输入,监测 feature map 的变化,或是观察 weight。可以使用print(type(Image.open(image_path)))查看图片的类型(PIL)。可以利用Opencv读取图片,获得numpy型图片数据。或者转为 tensorflow型。

参数:

  • tag: 就是保存图的名称

  • img_tensor:图片的类型要是torch.Tensor, numpy.array, or string这三种

  • golbal_step:第几张图片

  • dataformats=‘CHW’,默认CHW,tensor是CHW,numpy是HWC,C:channel H:high W:weight. 从PIL到numpy,需要在add_image()中指定shape中每一个数字/维度的含义

从PIL到numpy,需要在add_image()中指定shape中每一个数字/维度的含义

from torch.utils.tensorboard import SummaryWriter
from PIL import Image
import numpy as np


writer = SummaryWriter("logs")  # 创建SummaryWriter() 类实例,将对应的事件文件存储到 logs 文件中

image_path = "dataset/train/ants_image/0013035.jpg"
img_PIL = Image.open(image_path)
img_array = np.array(img_PIL) #PIL转为numpy型
print(type(img_array))
print(img_array.shape)

add_image(): 绘制图片,可用于检查模型的输入,监测 feature map 的变化,或是观察 weight。
参数:
    tag: 就是保存图的名称
    img_tensor:图片的类型要是torch.Tensor, numpy.array, or string这三种
    golbal_step:第几张图片
    dataformats=‘CHW’,默认CHW,tensor是CHW,numpy是HWC,C:channel H:high W:weight. 
writer.add_image("test", img_array, 1, dataformats='HWC')   # 不指定 dataformats='HWC' 会出现错误

writer.close()

4.3 Transforms的使用

用于对图像进行预处理和数据增强操作,如调整图像大小、中心裁剪、随机裁剪、随机水平翻转、归一化、将 PIL 图像转换为 Tensor 等。

from torchvision import transforms

在这里插入图片描述

4.3.1 图片类型转化Tensor

使用transforms的ToTensor()进行图片类型的转化。transforms.ToTensor()可以将PIL和numpy格式的数据从[0,255]范围转换到[0,1] ,具体做法其实就是将原始数据除以255。另外原始数据的shape是(H x W x C),通过transforms.ToTensor()后shape会变为(C x H x W)。

查看transforms的源代码,发现其实现了__call__方法,所以tensor_trans = transforms.ToTensor() ,tensor_img = tensor_trans(img)直接传入img调用了其中的__call__方法。在 Python 中,call 是一个特殊方法(也称为魔术方法或双下划线方法),用于使对象可以像函数一样被调用。当你在一个对象上调用 obj() 时,Python 解释器会查找该对象的 call 方法并调用它。

from torchvision import transforms
from PIL import Image
img_path = "C:\\Users\\Sen\\Desktop\\pytorch\\Pytorch\\data\\train\\bees_image\\16838648_415acd9e3f.jpg"
img = Image.open(img_path)
print(type(img))
tensor_trans = transforms.ToTensor() # transforms.ToTensor() 这一步相当于实例化 返回totensor的对象
tensor_img = tensor_trans(img) # 图片转化
print(type(tensor_img))

在这里插入图片描述

4.3.2 Tensor数据类型

神经网络专用的数据类型,包含了许多神经网络需要的参数。

4.4常见的transforms

在这里插入图片描述

4.4.1 Normalize

使用Normalize对图像进行归一化,对每个通道进行归一化:(输入值–均值)/ 标准差。output[channel] = (input[channel] - mean[channel]) / std[channel]。这里[channel]的意思是指对特征图的每个通道都进行这样的操作。【mean为均值,std为标准差】。

假设三个通道的均值和标准差都为0.5,计算公式如下图所示:
在这里插入图片描述

from torch.utils.tensorboard import SummaryWriter
from PIL import Image
from torchvision import transforms

writer = SummaryWriter("logs") # 日志文件存储位置
img_path = "C:\\Users\\Sen\\Desktop\\pytorch\\Pytorch教程\\data\\train\\bees_image\\16838648_415acd9e3f.jpg"
img = Image.open(img_path)
tensor_trans = transforms.ToTensor() 
tensor_img = tensor_trans(img)
trans_norm = transforms.Normalize([0.5,0.5,0.5],[0.5,0.5,0.5])
img_norm = trans_norm(tensor_img)
print(tensor_img[0][0][0])
print(img_norm[0][0][0])
writer.add_image("Normalize",img_norm)
writer.close()

4.4.2 transform.Resize()的使用

注意图片数据类型,通过Image.open读取的是PIL类型的
transform.Resize() 可以处理 PIL 图像对象,也可以处理张量类型的数据

from PIL import Image
from torchvision import transforms
img_path = "C:\\Users\\Sen\\Desktop\\pytorch\\Pytorch教程\\data\\train\\bees_image\\16838648_415acd9e3f.jpg"
img = Image.open(img_path)
print("图片原始大小,读取为PIL类型",img.size)
trans_resize = transforms.Resize((512,512))
# PIL -> resize -> img_resize PIl
img_resize = trans_resize(img)
print("对PIL类型进行Resize",img_resize)
tensor_trans = transforms.ToTensor() 
img_resize PIl -> totensor -> img_resize tensor
img_resize = tensor_trans(img_resize)
print("将PIL Reszie的图片转换为Tensor",img_resize)
trans_resize2 = transforms.Resize((256,256))
img_resize = trans_resize(img_resize)
print("对tensor类型的数据进行Resize",img_resize)

4.4.3 利用Compose进行resize

Compose用于组合多个图像转换(transform)操作。通过 Compose,可以创建一个转换流程,这个流程可以按顺序执行多个图像处理操作,这些操作可以包括缩放、裁剪、归一化等,其需要的参数是一个列表,其元素类型是transforms类型。
格式Compose([transforms参数1,transforms参数2,…])

from PIL import Image
from torchvision import transforms
img_path = "C:\\Users\\Sen\\Desktop\\pytorch\\Pytorch教程\\data\\train\\bees_image\\16838648_415acd9e3f.jpg"
img = Image.open(img_path)
print(img)
trans_resize2 = transforms.Resize(512)
trans_totensor = transforms.ToTensor() 
trans_compose = transforms.Compose([trans_resize2,trans_totensor])
img_resize_2 = trans_compose(img)
print(img_resize_2)

4.4.4 随机裁剪RandomCrop

RandomCrop 是 PyTorch 中用于图像数据增强(data augmentation)的函数之一,它可以在图像或张量的随机位置裁剪出指定大小的区域。transforms.RandomCrop((128, 128))会随机在输入图像中裁剪出大小为 128x128 的区域,并返回裁剪后的图像对象。

from torch.utils.tensorboard import SummaryWriter
from PIL import Image
from torchvision import transforms

writer = SummaryWriter("logs") # 日志文件存储位置
img_path = "C:\\Users\\Sen\\Desktop\\pytorch\\Pytorch教程\\data\\train\\bees_image\\16838648_415acd9e3f.jpg"
img = Image.open(img_path)
print(img)
trans_random = transforms.RandomCrop(30)
trans_totensor = transforms.ToTensor() 
trans_compose_2 = transforms.Compose([trans_random,trans_totensor])
for i in range(10):
    img_crop = trans_compose_2(img)
    writer.add_image("RandomCrop",img_crop,i)
    
writer.close()

4.5 torchvision中的数据集使用

本节主要是dataset。dataset就是告诉程序数据集在什么地方,有多少数据等。

import torchvision
from torchvision import transforms
from torch.utils.tensorboard import SummaryWriter

writer = SummaryWriter("logs") # 日志文件存储位置
dataset_transform = transforms.Compose([
    transforms.ToTensor() 
])
train_set = torchvision.datasets.CIFAR10(root="./dataset",train=True,transform=dataset_transform,download=True)
test_set = torchvision.datasets.CIFAR10(root="./dataset",train=False,transform=dataset_transform,download=True)
print(test_set[0])
img, target = test_set[0]  # target对应类的编号 对应cat
print(img)
print(target)
print(test_set.classes[target])

for i in range(10):
    img, target = test_set[i]
    writer.add_image("torchvision",img,i)

4.6 DataLoader的使用

drop_last=True 表示如果最后一个批次的样本数量小于批次大小,则丢弃该批次;而 drop_last=False 则表示保留最后一个不完整的批次

import torchvision
from torchvision import transforms
from torch.utils.data import DataLoader
dataset_transform = transforms.Compose([
    transforms.ToTensor() 
])
# 准备的测试数据集
test_set = torchvision.datasets.CIFAR10(root="./dataset",train=False,transform=dataset_transform, download=True)
test_loader = DataLoader(dataset=test_set, batch_size=4, shuffle=True, num_workers=0, drop_last=False)
img, target = test_set[0]
print("单个img:",img.shape)
print("单个target:",target)

for data in test_loader:
    imgs,targets = data
    print(imgs.shape)
    print(targets)

4.7 神经网络

常用的的包torch.nn,神经网络的基类Module,定义的模型都需要集成该类nn.Module。自己定义的模型需要实现__init__和forward函数,举例:

import torch
from torch import nn
class Tudui(nn.Module):
    def __init__(self):
        super().__init__()
        
    def forward(self, input):
        output = input +1
        return output
tudui = Tudui()
x = torch.tensor(1.0)
myout = tudui(x)
print(myout)

总结

本周系统性地研究了深度学习核心算法与PyTorch实践应用。在算法层面,深入分析了梯度下降的优化方法包括随机梯度下降与动量法,探讨了反向传播的计算图实现机制,并对比了Sigmoid、Tanh和ReLU等激活函数的特性及其对训练过程的影响。在PyTorch实践环节,掌握了数据加载流程涉及Dataset与DataLoader的配合使用,实现了TensorBoard的训练可视化监控,实践了Transforms数据预处理方法如Resize、Normalize和RandomCrop,并完成了神经网络模块的构建与基础训练流程。通过理论推导与代码实践的结合,深化了对模型训练机制的理解,为后续研究优化器策略、卷积神经网络应用以及模型部署技术奠定了坚实基础。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值