第十五周:机器学习

news2024/11/25 11:04:08

目录

摘要

abstrct

一、HW3——食物图片分类CNN

二、GAN计算推导

1、引入 

2、最大似然估计

3、divergence的计算

4、总结

三、GAN的架构——fGAN

1、f-divergence  

2、共轭函数

3、connetction with GAN

总结 


摘要

本周进一步学习了GAN基本原理,主要以GAN的计算推导和fGAN为主,回顾了最大似然函数和JS-divergence。并且动手实践了李宏毅机器学习的作业3,从数据集的处理、模型及其参数的定义以及训练和测试数据集等各方面进行了详细的代码分析。 

abstrct

This week, we further studied GAN fundamentals, mainly focusing on the computational derivation of GAN and fGAN, reviewing the maximum likelihood function and JS-divergence. we also practiced Hongyi Li's Machine Learning Assignment 3, which provides a detailed code analysis of various aspects, such as the processing of datasets, the definition of the model and its parameters, as well as the training and testing dataset. 

一、HW3——食物图片分类CNN

数据集的处理

class FoodDataset(Dataset):

    def __init__(self,path,tfm=test_tfm,files = None):
        super(FoodDataset).__init__()
        self.path = path
        self.files = sorted([os.path.join(path,x) for x in os.listdir(path) if x.endswith(".jpg")])
        if files != None:
            self.files = files

        self.transform = tfm

    def __len__(self):
        return len(self.files)

    def __getitem__(self,idx):
        fname = self.files[idx]
        im = Image.open(fname)
        im = self.transform(im)

        try:
            label = int(fname.split("/")[-1].split("_")[0])
        except:
            label = -1 # test has no label

        return im,label

初始化方法:

path——数据集的路径

files——加载数据集的文件列表

tfm——数据增强

__len__方法:

返回数据集中的图像数量

__getitem__方法: 

返回图像及其标签(做完数据增强)

数据增强

test_tfm = transforms.Compose([
    transforms.Resize((128, 128)),
    transforms.ToTensor(),
])

train_tfm = transforms.Compose([
    transforms.Resize((128, 128)),
    transforms.ToTensor(),
])

ToTensor()是最后一行执行的,旨在于将数据类型转化为tensor张量。其他数据增强的方法有翻转、旋转、缩放、平移、裁剪、颜色变换、噪声添加、模糊和仿射变换等,目的是为了提高模型的泛化能力,解决了数据少的问题并且有效防止了过拟合的问题。

模型的定义——CNN分类

class Classifier(nn.Module):
    def __init__(self):
        super(Classifier, self).__init__()# torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride, padding)
        self.cnn = nn.Sequential(
            nn.Conv2d(3, 64, 3, 1, 1),  # [64, 128, 128]
            nn.BatchNorm2d(64),
            nn.ReLU(),
            nn.MaxPool2d(2, 2, 0),      # [64, 64, 64]

            nn.Conv2d(64, 128, 3, 1, 1), # [128, 64, 64]
            nn.BatchNorm2d(128),
            nn.ReLU(),
            nn.MaxPool2d(2, 2, 0),      # [128, 32, 32]

            nn.Conv2d(128, 256, 3, 1, 1), # [256, 32, 32]
            nn.BatchNorm2d(256),
            nn.ReLU(),
            nn.MaxPool2d(2, 2, 0),      # [256, 16, 16]

            nn.Conv2d(256, 512, 3, 1, 1), # [512, 16, 16]
            nn.BatchNorm2d(512),
            nn.ReLU(),
            nn.MaxPool2d(2, 2, 0),       # [512, 8, 8]

            nn.Conv2d(512, 512, 3, 1, 1), # [512, 8, 8]
            nn.BatchNorm2d(512),
            nn.ReLU(),
            nn.MaxPool2d(2, 2, 0),       # [512, 4, 4]
        )
        self.fc = nn.Sequential(
            nn.Linear(512*4*4, 1024),
            nn.ReLU(),
            nn.Linear(1024, 512),
            nn.ReLU(),
            nn.Linear(512, 11)
        )

    def forward(self, x):
        out = self.cnn(x)
        out = out.view(out.size()[0], -1)
        return self.fc(out)

该模型含有5个卷积层和1个全连接层。”卷积+归一化+激活函数+最大池化“作为一个整体构成一层卷积层,全连接层将输出展开成一行做线性变换

训练模型参数的设置

device = "cuda" if torch.cuda.is_available() else "cpu"
model = Classifier().to(device)
batch_size = 64
n_epochs = 8
patience = 5 #早停机制:为了有效防止过拟合
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.0003, weight_decay=1e-5)

设置训练参数的值,并且初始化模型 

早停机制:一种机器学习模型调优策略,提升调优效率。是一种正则化形式,用于在使用梯度下降等迭代法训练学习器时避免过拟合。这种方法会更新学习器,使其每次迭代都能更好地适应训练数据。参数是patience

 加载数据集

train_set = FoodDataset("/kaggle/input/dataset/food-11/training", tfm=train_tfm)
train_loader = DataLoader(train_set, batch_size=batch_size, shuffle=True, num_workers=0, pin_memory=True)
valid_set = FoodDataset("/kaggle/input/dataset/food-11/validation", tfm=test_tfm)
valid_loader = DataLoader(valid_set, batch_size=batch_size, shuffle=True, num_workers=0, pin_memory=True)

训练前,加载训练集和验证集并且分别进行数据增强,设置好其参数 

开始训练

#初始化
stale = 0
best_acc = 0

for epoch in range(n_epochs):

    #开始训练训练集
    model.train()

    #记录损失函数和精确度
    train_loss = []
    train_accs = []

    for batch in tqdm(train_loader):
        imgs, labels = batch  #一组图像数据及其所对应的标签是一个batch
        #imgs = imgs.half()
        #print(imgs.shape,labels.shape)

        logits = model(imgs.to(device)) #模型在最后一层输出的原始预测值


        loss = criterion(logits, labels.to(device)) #采用交叉熵来计算损失
        acc = (logits.argmax(dim=1) == labels.to(device)).float().mean()  #计算当前batch的准确度

        optimizer.zero_grad()  #梯度清零
        loss.backward()  #计算梯度下降的参数
        grad_norm = nn.utils.clip_grad_norm_(model.parameters(), max_norm=10)  #裁剪梯度范数:防止梯度爆炸
        optimizer.step() #更新梯度参数

        
        #记录损失和精确度
        train_loss.append(loss.item())
        train_accs.append(acc)

    #计算损失和精确度的均值
    train_loss = sum(train_loss) / len(train_loss)
    train_acc = sum(train_accs) / len(train_accs)

    print(f"[ Train | {epoch + 1:03d}/{n_epochs:03d} ] loss = {train_loss:.5f}, acc = {train_acc:.5f}")


    #开始训练验证集
    model.eval()

    valid_loss = []
    valid_accs = []

    for batch in tqdm(valid_loader):

 
        imgs, labels = batch

        with torch.no_grad():   #验证集的迭代不需要梯度下降
            logits = model(imgs.to(device))

        loss = criterion(logits, labels.to(device))  #交叉熵计算损失
        acc = (logits.argmax(dim=1) == labels.to(device)).float().mean()  #计算精确度

        # 记录损失和精确度
        valid_loss.append(loss.item())
        valid_accs.append(acc)

    #计算损失和精确度的均值
    valid_loss = sum(valid_loss) / len(valid_loss)
    valid_acc = sum(valid_accs) / len(valid_accs)

    print(f"[ Valid | {epoch + 1:03d}/{n_epochs:03d} ] loss = {valid_loss:.5f}, acc = {valid_acc:.5f}")


    # 以当前验证集上的表现来更新日志
    if valid_acc > best_acc:
        with open(f"./{_exp_name}_log.txt","a"):
            print(f"[ Valid | {epoch + 1:03d}/{n_epochs:03d} ] loss = {valid_loss:.5f}, acc = {valid_acc:.5f} -> best")
    else:
        with open(f"./{_exp_name}_log.txt","a"):
            print(f"[ Valid | {epoch + 1:03d}/{n_epochs:03d} ] loss = {valid_loss:.5f}, acc = {valid_acc:.5f}")


    # 如果说验证集的表现更佳,那么将将该准确度替代当前记录中的准确度
    if valid_acc > best_acc:
        print(f"Best model found at epoch {epoch}, saving model")
        torch.save(model.state_dict(), f"{_exp_name}_best.ckpt") # only save best to prevent output memory exceed error
        best_acc = valid_acc
        stale = 0
    else:
        stale += 1
        if stale > patience:
            print(f"No improvment {patience} consecutive epochs, early stopping")
            break

训练的数据集分为训练集和验证集,它们的基本操作都是不停地迭代各个batch得到训练结果,接着将训练结果与真实标签做交叉熵损失和精确度计算。但是二者有一定的区别,训练集需要进行梯度下降,而验证集不需要。 

以下是更新日志中的精确度的两种情况:

case1:第六轮训练中最终更新的精确度是0.57340,验证集并没有比它更优,所以不进行log中acc的跟新

case2:第四轮训练中最终跟新的准确度是0.55971,最后第六轮训练验证集比其更优,所以对log中的acc进行更新

测试训练效果并保存

#测试集数据加载
set = FoodDataset("/kaggle/input/dataset/food-11/testing", tfm=test_tfm)
test_loader = DataLoader(test_set, batch_size=batch_size, shuffle=False, num_workers=0, pin_memory=True)

#测试集放入模型中预测
model_best = Classifier().to(device)  #初始化模型并加载至最佳状态
model_best.load_state_dict(torch.load(f"{_exp_name}_best.ckpt"))  #加载之前保存的最佳模型状态字典
model_best.eval()   #将模型设置为评估模式
prediction = []   #预测结果列表,包含每个预测中概率最高的类别索引
with torch.no_grad():
    for data,_ in tqdm(test_loader):
        test_pred = model_best(data.to(device))  #测试数据放入最佳模型中进行预测
        test_label = np.argmax(test_pred.cpu().data.numpy(), axis=1) #获取每个预测中概率最高的类别的索引
        prediction += test_label.squeeze().tolist()  #减少预测结果的维度def 

#创建一个csv文件用来保存测试集的预测结果
pad4(i):                               #为了保证序号的一致,不足4位的左补零
    return "0"*(4-len(str(i)))+str(i)    
df = pd.DataFrame()
df["Id"] = [pad4(i) for i in range(len(test_set))]   #id是测试集中的图片序号,category是预测结果
df["Category"] = prediction
df.to_csv("submission.csv",index = False)

与前面训练数据集相同,测试数据集也需要加载测试集并将其放入训练出的最好的模型中。最终得到测试集的预测结果,结果如下: 

可视化数据增强

import torchvision.transforms as transforms

# 定义一个包含多种数据增强技术的train_tfm
train_tfm = transforms.Compose([
    transforms.RandomResizedCrop(224),  # 随机调整大小并裁剪到224x224
    transforms.RandomHorizontalFlip(p=0.5),  # 以0.5的概率随机水平翻转
    transforms.RandomVerticalFlip(p=0.5),  # 以0.5的概率随机垂直翻转
    transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.1),  # 随机调整亮度、对比度、饱和度和色调
    transforms.RandomRotation(degrees=15),  # 随机旋转最多15度
    transforms.ToTensor(),  # 将图像转换为张量
    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])  # 使用均值和标准差进行标准化
])
# 加载图像
image_path = '/kaggle/input/dataset/food-11/training/0_0.jpg'  # 替换为你的图像路径
image = Image.open(image_path)

# 应用数据增强并可视化
fig, axes = plt.subplots(nrows=2, ncols=3, figsize=(15, 10))
for i, ax in enumerate(axes.flat):
    # 应用数据增强
    augmented_image = train_tfm(image)
    
    # 反标准化以便可视化
    mean = torch.tensor([0.485, 0.456, 0.406])
    std = torch.tensor([0.229, 0.224, 0.225])
    augmented_image_unnormalized = augmented_image * std[:, None, None] + mean[:, None, None]
    
    # 转换为PIL图像以便显示
    augmented_image_pil = transforms.ToPILImage()(augmented_image_unnormalized)
    
    # 显示图像
    ax.imshow(augmented_image_pil)
    ax.axis('off')
    ax.set_title(f'Augmented {i+1}')

plt.tight_layout()
plt.show()

可视化结果如下: 

上面一共进行了6次迭代,代表了原图像经过了6次由随机参数构成的数据增强变换,每一次都需要进行train_tfm中的7个transform

最终的输出

 

二、GAN计算推导

1、引入 

前两周对GAN概念的理解可以看出,GAN主要就是将一组generator和discriminator不断优化的过程,二者的目标相互对立,但是可以促进对方的改进。 generator主要负责生成与真实图片相近的图片,discriminator主要负责判别真实图片和生成图片。GAN最终的目的就是生成比较像真实图片的图片,越像越好。 

假设P_GP_{data}分别代表生成数据的分布和真实数据的分布,Div(P_G,P_{data})是指两个分布之间的距离,”最优generator“是取得该距离最小值时的G^*,公式如下:

G^*=arg minDiv(P_G,P_{data})

问题:如何判断P_GP_{data}的分布最相似

解决:最大似然估计

2、最大似然估计

step1 给定真实数据分布P_{data}(x)

step2 假设生成数据分布P_G(x;\theta ),带有参数\theta\theta可以调整P_G(x;\theta )生成更多接近P_{data}(x)的数据

step3 最大似然估计 L=\prod_{i=1}^{m}P_G(x^i;\theta ),其中\theta^*是L取得最大值的参数

step4 计算\theta^*,如下:

问题:其中P_GP_{data}的分布都是未知的,如何计算?

解决:需要引入discriminator,判别器可以量出两个分布之间的距离

训练discriminator需要定义以上function,其中G是固定值。该训练函数类似于分类任务中的交叉熵损失函数的计算。最终需要”最优discriminator“是取得V(G,D)的最大值时的D^*,因为discriminator所做的是将D和G尽可能的分开,意味着两个分布的距离取最大值。

3、divergence的计算

最终发现Div(P_G,P_{data})转换成了JS-divergence

接着再将最优discriminator带入到Div(P_G,P_{data})中去,得到如下式子:

我们需要在不同的G上,找到D曲线最大值的地方(说明discriminator达到最优解),然后比较多个最大值谁更小,选择最小的为G^*(说明generator达到最优解)。

4、总结

 

二分类交叉熵

参考文章

论文GAN(生成对抗网络)的一些解读_对抗网络gan中文公式解读-CSDN博客

GAN 公式推导_生成对抗网络gan的公式-CSDN博客

三、GAN的架构——fGAN

1、f-divergence  

 

能够发现,随着函数f(x)的变化,f-divergence也会有所不同,会出现很多种形式的divergence,如下:

 

 

2、共轭函数

共轭函数:是函数的某种对偶变换。 

 

需要在不同的t上找到使得式子最大的x。首先固定一个t,接着不断调整x找到f^*的最大值。要想使得计算简化,就画出每个x的f^*函数式,在所有t的范围内找到最大值的f^*,如下图所示:

 

3、connetction with GAN

由上面的共轭函数不断地推导,再带入到f-divergence中去,最终得到了G^*的计算。如下: 

 

总结 

本周继续深入了GAN的学习,并且以代码实践来回顾了CNN的学习。下周将学习GAN中的半监督学习,并且继续动手代码实践。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2212163.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

element el-tree 自定义图标

除了自定义以外,下方代码还包含 tree自动展开 点击节点后节点聚焦 节点的click事件 节点查询 <template><el-inputplaceholder"请输入要查询的节点"v-model"filterText"clearable></el-input><el-treehighlight-currentclass&quo…

【RabbitMQ】RabbitMQ 的七种工作模式介绍

目录 1. Simple(简单模式) 2. Work Queue(工作队列) 3. Publish/Subscribe(发布/订阅) 4. Routing(路由模式) 5. Topics(通配符模式) 6. RPC(RPC通信) 7. Publisher Confirms(发布确认) 上一篇文章中我们简单认识了RabbitM1: 【RabbitMQ】RabbitMQ 的概念以及使用Rabb…

【Qt】窗口关闭提示框

在关闭QWdiget窗口时弹出提示框 重写**closeEvent**函数 void closeEvent(QCloseEvent* event) override;QMessageBox *msgBox new QMessageBox(QMessageBox::Question, "信息提示", "是否保存当前数据&#xff1f;", QMessageBox::Save | QMessageBox::N…

github克隆项目中的子模块submodule时遇到“无法访问远程仓库,请检查权限“

问题描述 在拉取仓库的时候发现了新东西。 仓库中有两个文件夹提示 点击之后&#xff0c;发现跳转到了另一个仓库 &#xff0c;原来这是仓库的子模块&#xff0c;第一次见&#xff0c;也就是仓库中包含了其他的的仓库&#xff0c;就是这么简单的原理。 但是在拉取仓库以后发现…

VScode环境配置

目录 好用插件推荐 1.Auto Rename Tag 2.openbrowser 3.实时预览&#xff08;推荐&#xff09; VSCode常用的快捷键 1. 快速复制一行 2.快速复制一行代码选定多个相同的单词 3. 添加多个光标 4. 全局替换某写单词 5. 快速定位到某一行 6. 选择某个区块 7. 放大缩…

高一全栈开发;国产 Arc 浏览器;Tauri 2.0 发布 | 生活周刊 #3

发现新应用 Vectorcraftr Vectorcraftr 提供免费可商用的插画库&#xff0c;风格有很多&#xff0c;自行食用 书立 一款功能强大、特性丰富的笔记软件&#xff0c;包含富文本&#xff0c;双链&#xff0c;表格&#xff0c;富目录树&#xff0c;WebDAV &#xff0c;自由导出等…

WPF 为button动态设置不同的模板

有时候需要动态的设置一些按钮的状态模板。使一个button显示不同的内容&#xff0c;比如Button未点击安装显示&#xff1a; 安装后显示&#xff1a; 可以通过设置button的content&#xff0c;通过content来设置不同的模板来实现功能&#xff0c;以下是代码&#xff1a; MainWi…

【消息队列】Kafka从入门到面试学习总结

国科大学习生活&#xff08;期末复习资料、课程大作业解析、大厂实习经验心得等&#xff09;: 文章专栏&#xff08;点击跳转&#xff09; 大数据开发学习文档&#xff08;分布式文件系统的实现&#xff0c;大数据生态圈学习文档等&#xff09;: 文章专栏&#xff08;点击跳转&…

CentOS7安装Gitlab服务

文章目录 前言一、安装依赖二、安装gitlab1、上传安装2、修改配置 三、启动gitlab服务四、修改密码五、设置为中文&#xff08;低版本有问题&#xff09;六、常用命令 前言 文中gitlab版本为&#xff1a; gitlab-ce-14.2.7 一、安装依赖 gitlab需要安装如下依赖&#xff0c;否…

Linux编辑器-vim的配置及其使用

vim是一种多模式的编辑器&#xff1a; 1.命令模式&#xff08;默认模式&#xff09;&#xff1a;用户所有的输入都会当作命令&#xff0c;不会当作文本输入。 2.插入模式&#xff1a;写代码&#xff0c; 按「 i 」切换进入插入模式「 insert mode 」&#xff0c;按 “i” 进入…

2024/10/13周报

文章目录 摘要Abstract文献阅读题目1. 背景与问题提出2. 提出的CLATT方法2.1 卷积神经网络&#xff08;CNN&#xff09;2.2 长短期记忆网络&#xff08;LSTM&#xff09;2.3 注意力机制2.4 滑动窗口方法 3. 实验设计与结果3.1 数据集3.2 实验基线与评价指标3.3 实验结果与分析 …

使用清华大学开源软件镜像站下载JDK

在软件开发和日常使用中&#xff0c;Java Development Kit&#xff08;JDK&#xff09;是不可或缺的一部分。它提供了Java运行环境和开发工具&#xff0c;使得开发者可以编写、编译和运行Java应用程序。本文将指导你如何从清华大学开源软件镜像站&#xff08;TUNA&#xff09;下…

通信工程学习:什么是UART通用异步收发器

UART&#xff1a;通用异步收发器 UART&#xff0c;全称Universal Asynchronous Receiver/Transmitter&#xff0c;即通用异步收发传输器&#xff0c;是一种广泛应用于嵌入式领域的串行、异步、全双工通信协议。以下是关于UART的详细介绍&#xff1a; 一、定义与特点 定义&…

数据分析:R语言计算XGBoost二分类模型的SHAP值

禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍SHAP用途计算方法:应用加载R包导入数据建模平均SHAP值计算单个样本的每个特征的SHAP值蜜蜂图依赖图单个样本的SHAP解释(Force Plot)其他方法计算SHAP值单个个体预测结果系统信息…

MLM之Llama-3:Llama 3.2的简介、安装和使用方法、案例应用之详细攻略

MLM之Llama-3&#xff1a;Llama 3.2的简介、安装和使用方法、案例应用之详细攻略 目录 Llama 3.2 简介 1、Llama 3.2 的特点 2、模型评估 轻量级指令调优基准 视觉指令调整基准 Llama 3.2 的安装和使用方法 1、下载模型 2. 开发环境准备 3. 使用模型进行推理和微调 4…

Ubuntu命令行快速部署C++语言的GDAL库

本文介绍在Linux系统的Ubuntu电脑中&#xff0c;在命令行中一句代码快速配置C 环境下的gdal库的方法。 在文章Ubuntu基于Docker快速配置GDAL的Python、C环境&#xff08;https://blog.csdn.net/zhebushibiaoshifu/article/details/133433838&#xff09;中&#xff0c;我们就介…

【JVM】内存模型

文章目录 内存模型的基本概念案例 程序计数器栈Java虚拟机栈局部变量表栈帧中局部变量表的实际状态栈帧中存放的数据有哪些 操作数栈帧数据 本地方法栈 堆堆空间是如何进行管理的? 方法区静态变量存储 直接内存直接内存的作用 内存模型的基本概念 在前面的学习中,我们知道了字…

施磊C++ | 进阶学习笔记 | 3.绑定器和函数对象、lambda表达式

三、绑定器和函数对象、lambda表达式 文章目录 三、绑定器和函数对象、lambda表达式3.1模板的完全特例化和非完全&#xff08;部分&#xff09;特例化1.完全特例化和非完全&#xff08;部分&#xff09;特例化2.模板的实参推演 3.2 C STL中的绑定器bind1stbind2nd自己实现一个b…

深度学习——线性神经网络(三、线性回归的简洁实现)

目录 3.1 生成数据集3.2 读取数据集3.3 定义模型3.4 初始化模型参数3.5 定义损失函数3.6 定义优化算法3.7 训练 在上一节中&#xff0c;我们通过张量来自定义式地进行数据存储和线性代数运算&#xff0c;并通过自动微分来计算梯度。实际上&#xff0c;由于数据迭代器、损失函数…

基于深度学习的西红柿成熟度检测系统

简介&#xff1a; 基于深度学习技术的西红柿成熟度检测系统是一种利用人工智能算法对西红柿成熟程度进行自动识别和分类的智能系统。该系统通过采集西红柿的图像数据&#xff0c;运用深度学习模型对图像中的西红柿进行特征提取和分析&#xff0c;从而实现对西红柿成熟度的准确判…