根据DCT特征训练CNN

记录一次改代码的挣扎经历:
        看了几篇关于DCT频域的深度模型文献,尤其是21年FcaNet:基于DCT 的attention model,咱就是说想试试将我模型的输入改为分组的DCT系数,然后就开始下面的波折了。

第一次尝试:

        我直接调用了库函数,然后出现问题了:这个库函数是应用在numpy数组上,得在CPU上处理。

from scipy.fftpack import dct, idct
...
dct_block = dct(dct(block, axis=2, norm='ortho'), axis=3, norm='ortho')   # [B,C,k,k]
...
block = idct(idct(dct_block, axis=2, norm='ortho'), axis=3, norm='ortho')    # [B,C,k,k]

第二次尝试:
        好吧,我先把数据调回CPU,处理后,再调回GPU,又有新问题了:这样做(将block从GPU转移至CPU)torch类型张量转换为numpy数组时,torch张量的梯度无法保存。

# 图像分块
...
# 将块转移到 CPU
block_cpu = block.cpu()        # [B,C,k,k]
# 在 CPU 上对块应用 DCT
dct_block_np = dct(dct(block_cpu.numpy(), axis=2, norm='ortho'), axis=3, norm='ortho')   # [B,C,k,k]
# 将结果传输回 GPU
dct_block = torch.from_numpy(dct_block_np).to(image.device)     # [B,C,k,k]

...

# 将块转移到 CPU
dct_block_cpu = dct_block.cpu()
# 在 CPU 上对块应用逆 DCT
block_np = idct(idct(dct_block_cpu.numpy(), axis=2, norm='ortho'), axis=3, norm='ortho')
# 将结果传输回 GPU
block = torch.from_numpy(block_np).to(dct_block.device)    # [B,C,k,k]

 第三次尝试:

        根据报错提醒,我进行以下改进,将block_cpu.numpy -> block_cpu.detach.numpy(),即忽略掉torch类型张量带着的梯度信息,哈哈,这样一改,梯度就丢失了,模型就不能反向传播进行更新训练了。

# 图像分块
...
# 将块转移到 CPU
block_cpu = block.cpu()        # [B,C,k,k]
# 在 CPU 上对块应用 DCT
dct_block_np = dct(dct(block_cpu.numpy(), axis=2, norm='ortho'), axis=3, norm='ortho')   # [B,C,k,k]
# 将结果传输回 GPU
dct_block = torch.from_numpy(dct_block_np).to(image.device)     # [B,C,k,k]

...

# 将块转移到 CPU
dct_block_cpu = dct_block.cpu()
# 在 CPU 上对块应用逆 DCT
block_np = idct(idct(dct_block_cpu.detach.numpy(), axis=2, norm='ortho'), axis=3, norm='ortho')
# 将结果传输回 GPU
block = torch.from_numpy(block_np).to(dct_block.device)    # [B,C,k,k]

第四次尝试:
        CPU上库函数不好用,那我自己写(借鉴)DCT变换的函数嘛,DCT就是输入k*k图像关于k*k个余弦基函数的加权和嘛:

 别人写的的8 x 8d的DCT和IDCT的实现:


class DCT8X8(nn.Module):
    """ Discrete Cosine Transformation
    Input:
        image(tensor): batch x height x width
    Output:
        dcp(tensor): batch x height x width
    """

    def __init__(self):
        super(DCT8X8, self).__init__()
        tensor = np.zeros((8, 8, 8, 8), dtype=np.float32)

        for x, y, u, v in itertools.product(range(8), repeat=4):
            tensor[x, y, u, v] = np.cos((2 * x + 1) * u * np.pi / 16) * np.cos((2 * y + 1) * v * np.pi / 16)

        alpha = np.array([1. / np.sqrt(2)] + [1] * 7)

        self.tensor = nn.Parameter(torch.from_numpy(tensor).float())
        self.scale = nn.Parameter(torch.from_numpy(np.outer(alpha, alpha) * 0.25).float())

    def forward(self, image):
        image = image - 128
        result = self.scale * torch.tensordot(image, self.tensor, dims=2)
        result.view(image.shape)
        return result



class IDCT8X8(nn.Module):
    """ Inverse discrete Cosine Transformation
    Input:
        dcp(tensor): batch x height x width
    Output:
        image(tensor): batch x height x width
    """

    def __init__(self):
        super(IDCT8X8, self).__init__()
        alpha = np.array([1. / np.sqrt(2)] + [1] * 7)
        self.alpha = nn.Parameter(torch.from_numpy(np.outer(alpha, alpha)).float())
        tensor = np.zeros((8, 8, 8, 8), dtype=np.float32)
        for x, y, u, v in itertools.product(range(8), repeat=4):
            tensor[x, y, u, v] = np.cos((2 * u + 1) * x * np.pi / 16) * np.cos((2 * v + 1) * y * np.pi / 16)
        self.tensor = nn.Parameter(torch.from_numpy(tensor).float())

    def forward(self, image):
        image = image * self.alpha
        result = 0.25 * torch.tensordot(image, self.tensor, dims=2) + 128
        result.view(image.shape)
        return result

我根据上述改的任意block_size的DCT和IDCT:

class DCTCustom(nn.Module):
    """Customizable Discrete Cosine Transformation
    Input:
        image(tensor): batch x height x width
    Output:
        dct(tensor): batch x height x width
    """

    def __init__(self, input_size=8):
        super(DCTCustom, self).__init__()
        self.input_size = input_size
        tensor = np.zeros((input_size, input_size, input_size, input_size), dtype=np.float32)

        for x, y, u, v in itertools.product(range(input_size), repeat=4):
            tensor[x, y, u, v] = np.cos((2 * x + 1) * u * np.pi / (2 * input_size)) * np.cos((2 * y + 1) * v * np.pi / (2 * input_size))

        alpha = np.array([1. / np.sqrt(2)] + [1] * (input_size - 1))

        self.tensor = nn.Parameter(torch.from_numpy(tensor).float())
        self.scale = nn.Parameter(torch.from_numpy(np.outer(alpha, alpha) * 0.25).float())

    def forward(self, image):
        image = image - 128
        result = self.scale * torch.tensordot(image, self.tensor, dims=2)
        result = result.view(image.shape)  # Corrected line
        return result



class IDCTCustom(nn.Module):
    """ Inverse discrete Cosine Transformation
    Input:
        dcp(tensor): batch x height x width
    Output:
        image(tensor): batch x height x width
    """

    def __init__(self, block_size=8):
        super(IDCTCustom, self).__init__()
        self.block_size = block_size

        # Compute alpha coefficients
        alpha = np.array([1. / np.sqrt(2)] + [1] * (block_size - 1))
        self.alpha = nn.Parameter(torch.from_numpy(np.outer(alpha, alpha)).float())

        # Compute tensor for IDCT
        tensor = np.zeros((block_size, block_size, block_size, block_size), dtype=np.float32)
        for x, y, u, v in itertools.product(range(block_size), repeat=4):
            tensor[x, y, u, v] = np.cos((2 * u + 1) * x * np.pi / (2 * block_size)) * np.cos(
                (2 * v + 1) * y * np.pi / (2 * block_size)
            )
        self.tensor = nn.Parameter(torch.from_numpy(tensor).float())

    def forward(self, image):
        if image.shape[-2] % self.block_size != 0 or image.shape[-1] % self.block_size != 0:
            raise ValueError("Input dimensions must be divisible by the block size.")

        # Apply IDCT
        image = image * self.alpha
        result = 0.25 * torch.tensordot(image, self.tensor, dims=2) + 128
        result = result.view(image.shape)
        return result

        不出意外的话,问题又出现了,我对一个torch.ones((2,3,k,k))的张量进行DCT,再IDCT恢复。当k=8时(即block_size=8x8)时,能够完全恢复,但当k!=8(=16、32)时,经IDCT后无法恢复原始输入,懵。

第五次尝试(hh):
        突然!我发现了torch内置的DCT函数!可以再GPU上实现DCT。

torch-dct · PyPI

import torch_dct as dct

# 图像分块    # [B,C,H,W]
    ...        # [B,C,k,k]
    # dct
    block = dct.dct_2d(block)     # [B,C,k,k]

    ...
    # idct
    block = dct.idct_2d(block)        # [B,C,k,k]

 然后又有问题了:
        我的模型开始训练后,我发现我的每个epoch的loss都为NAN...

        然后我打印了DCT输出,发现DCT系数长这个样子,CNN不高兴好好训练吧。

        我们再想想办法将输入数据归一化到范围[0, 1]或[-1, 1]之间,再喂给CNN吧。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

在Centos7中利用Shell脚本:实现MySQL的数据备份

目录 自动化备份MySQL 一.备份数据库脚本 1.创建备份目录 2.创建脚本文件 3.新建配置文件(连接数据库的配置文件) 4.给文件权限(mysql_backup.sh) ​编辑 5.执行命令 (mysql_backup.sh) ​编辑 二.数据库通过备份恢复 1.创建脚…

多维时序 | MATLAB实现SSA-BiLSTM麻雀算法优化双向长短期记忆神经网络多变量时间序列预测

多维时序 | MATLAB实现SSA-BiLSTM麻雀算法优化双向长短期记忆神经网络多变量时间序列预测 目录 多维时序 | MATLAB实现SSA-BiLSTM麻雀算法优化双向长短期记忆神经网络多变量时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.MATLAB实现SSA-BiLSTM麻雀算法优化…

k8s的二进制部署: 源码包部署

服务器IP软件包k8s--master0120.0.0.61kube-aplserver,kube-controer-manager,kube-scheduler,etcdk8s--master0220.0.0.62kube-controer-manager,kube-schedulernode节点0120.0.0.62kubelet,kube-proxy,et…

第九部分 图论

目录 例 相关概念 握手定理 例1 图的度数列 例 无向图的连通性 无向图的连通度 例2 例3 有向图D如图所示,求 A, A2, A3, A4,并回答诸问题: 中间有几章这里没有写,感兴趣可以自己去学,组合数学跟高中差不多&#xff0c…

目标检测-Two Stage-SPP Net

文章目录 前言一、SPP Net 的网络结构和流程二、SPP的创新点总结 前言 SPP Net:Spatial Pyramid Pooling Net(空间金字塔池化网络) SPP-Net是出自何凯明教授于2015年发表在IEEE上的论文-《Spatial Pyramid Pooling in Deep ConvolutionalNetw…

设计模式(4)--对象行为(5)--中介者

1. 意图 用一个中介对象来封装一系列的对象交互。 中介者使各对象不需要显式地相互引用,从而使其耦合松散, 而且可以独立地改变它们之间的交互。 2. 四种角色 抽象中介者(Mediator)、具体中介者(Concrete Mediator)、抽象同事(Colleague)、 具体同事(Co…

https密钥认证、上传镜像实验

一、第一台主机通过https密钥对认证 1、安装docker服务 (1)安装环境依赖包 yum -y install yum-utils device-mapper-persistent-data lvm2 (2)设置阿里云镜像源 yum-config-manager --add-repo http://mirrors.aliyun.com/do…

时序预测 | Matlab实现SSA-CNN-LSTM麻雀算法优化卷积长短期记忆神经网络时间序列预测

时序预测 | Matlab实现SSA-CNN-LSTM麻雀算法优化卷积长短期记忆神经网络时间序列预测 目录 时序预测 | Matlab实现SSA-CNN-LSTM麻雀算法优化卷积长短期记忆神经网络时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 MATLAB实现SSA-CNN-LSTM麻雀算法优化卷积长短…

中伟视界:燃气站的烟火、安全帽、抽烟、打电话检测等AI算法的工作原理详解

人工智能(AI)技术在各行各业中的应用越来越广泛,燃气站的安全管理也在逐步引入AI算法。本文将详细介绍AI算法在燃气站安全管理中的应用,包括烟火检测、安全帽识别、抽烟、打电话检测等方面的工作原理。 烟火检测是燃气站安全管理中…

Java之网络编程

一、什么是网络编程 在网络通信协议下,不同计算机上运行的程序,可以进行数据传输 二、常见的网络架构 1、B/S :Browser/Server 只需要一个浏览器,用户通过不同的网址,客户访问不同的服务器。 例如:京东&am…

redis,memcached,nginx网络组件,网络编程——reactor的应用

目录 目标网络编程关注的问题连接的建立连接的断开消息的到达消息发送完毕 网络 IO 职责检测 IO检测 io剖析 操作 IO 阻塞IO 和 非阻塞IOIO 多路复用epoll结构以及接口 reactor编程连接建立连接断开数据到达数据发送完毕 reactor 应用:后续补充源码解析单 reacrtor多…

JVM高频面试题(2023最新版)

JVM面试题 1、JVM内存区域 Jvm包含两个子系统和两个组件。 1.1子系统 Class loader(类加载器):根据给定的全限定名类名(java.lang.object)来装载class文件到Runtime data area(运行时数据区)…

flask文件夹列表改进版--Bug追踪

把当前文件夹下的所有文件夹和文件列出来,允许点击返回上层目录,允许点击文件夹进入下级目录并显示此文件夹内容 允许点击文件进行下载 from flask import Flask, render_template, send_file, request, redirect, url_for import osapp Flask(__name_…

阿里云自建官方Docker仓库镜像提交拉取方法

文章目录 发布镜像到DockerHub发布镜像到自建Docker仓库(Harbor)修改配置文件在Linux服务器中登录Docker打TAGPUSH提交镜像PULL拉取镜像 发布镜像到阿里云容器服务在Linux服务器中登录DockerPUSH提交镜像PULL拉取镜像 发布镜像到DockerHub 本地我们镜像命名可能会不规范&#…

SpringCloud 整合 Canal+RabbitMQ+Redis 实现数据监听

1Canal介绍 Canal 指的是阿里巴巴开源的数据同步工具,用于数据库的实时增量数据订阅和消费。它可以针对 MySQL、MariaDB、Percona、阿里云RDS、Gtid模式下的异构数据同步等情况进行实时增量数据同步。 当前的 canal 支持源端 MySQL 版本包括 5.1.x , 5.5.x , 5.6.…

【面试】Java中的多种设计模式(十种主要设计模式)

Java中的多种设计模式(十种主要设计模式) 文章概述 设计模式是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。它是软件工程中常见问题的解决方案的一种描述或模板。设计模式可以提供一种通用的、可重用的解决方案,帮助开发…

16.Redis 高级数据类型 + 网站数据统计

目录 1.Redis 高级数据类型 2.网站数据统计 2.1 业务层 2.2 表现层 2.2.1 记录数据 2.2.2 查看数据 1.Redis 高级数据类型 HyperLogLog:采用一种基数算法,用于完成独立总数的统计;占据空间小,无论统计多少个数据&#xff0…

PYTHON基础:最小二乘法

最小二乘法的拟合 最小二乘法是一种常用的统计学方法,用于通过在数据点中找到一条直线或曲线,使得这条直线或曲线与所有数据点的距离平方和最小化。在线性回归中,最小二乘法被广泛应用于拟合一条直线与数据点之间的关系。 对于线性回归&…

华为——使用ACL限制内网主机访问外网网站示例

组网图形 图1 使用ACL限制内网主机访问外网网站示例 ACL简介配置注意事项组网需求配置思路操作步骤配置文件 ACL简介 访问控制列表ACL(Access Control List)是由一条或多条规则组成的集合。所谓规则,是指描述报文匹配条件的判断语句&#…

RFID技术在汽车制造:提高生产效率、优化物流管理和增强安全性

RFID技术在汽车制造:提高生产效率、优化物流管理和增强安全性 随着科技的进步,物联网技术已经深入到各个领域,尤其在制造业中,RFID技术以其独特的优势,如高精度追踪、实时数据收集和自动化操作,正在改变传统的生产方式…