Pytorch基础知识和函数的学习:图像卷积的理解和实践

卷积的基本概念

什么是卷积
        卷积是深度学习中的一个重要概念,特别是在计算机视觉任务中广泛应用。
        卷积操作是通过一个卷积核(也称为滤波器)在输入数据上滑动,进行局部特征提取的过程。PyTorch提供了强大的卷积功能支持。
卷积计算的基础知识
原来卷积是这么计算的_卷积计算-CSDN博客,个人认为这篇文章是非常优秀的,形象解释了卷积的基本概念和计算过程。
PyTorch中的卷积层:
        torch.nn.Conv1d: 一维卷积
        torch.nn.Conv2d: 二维卷积
        torch.nn.Conv3d: 三维卷积
        主要参数:
        
in_channels: 输入的通道数
        out_channels: 输出的通道数
        kernel_size: 卷积核的大小
        stride: 卷积步长
        padding: 输入填充
        dilation: 卷积核元素之间的间距
        groups: 控制输入和输出之间的连接
        bias: 是否添加偏置

一个简单的一维卷积DEMO:

import torch
import torch.nn as nn

# 定义一个1维Tensor,并调整其形状为(批次大小, 通道数, 序列长度)
input_tensor = torch.tensor([[[1.0, 2.0, 3.0, 4.0, 5.0]]])
# 定义一个简单的卷积层
conv_layer = nn.Conv1d(in_channels=1, out_channels=1, kernel_size=3, stride=1, padding=1)

# 应用卷积操作
output_tensor = conv_layer(input_tensor)
print(output_tensor)

 输出结果:

tensor([[[1.6147, 2.1414, 2.6681, 3.1949, 1.7116]]],
       grad_fn=<SqueezeBackward1>)

多运行两次:

tensor([[[-0.6965, -0.2377,  0.2211,  0.6798,  2.4817]]],
       grad_fn=<SqueezeBackward1>)
tensor([[[1.2291, 2.5095, 3.7900, 5.0704, 3.9702]]],
       grad_fn=<SqueezeBackward1>)

       可以看到,每次运行的输出结果并不相同,原因是如果不指定卷积核和偏置值,它就用随机数的卷积核和偏置值来进行卷积操作。在PyTorch的实际应用中,卷积核(也就是卷积层的权重)以及偏置值是可以学习的,也就是说,权重值和偏置值是在训练过程中通过优化算法自动调整的。

我们可以通过下面的方法查看卷积层的权重和偏置:

import torch
import torch.nn as nn

# 定义一个1维Tensor,并调整其形状为(批次大小, 通道数, 序列长度)
input_tensor = torch.tensor([[[1.0, 2.0, 3.0, 4.0, 5.0]]])
# 定义一个简单的卷积层
conv_layer = nn.Conv1d(in_channels=1, out_channels=1, kernel_size=3, stride=1, padding=1)

# 应用卷积操作
output_tensor = conv_layer(input_tensor)
print(f'卷积核的权重{conv_layer.weight.data}')   # 打印权重
print(f'偏置值{conv_layer.bias.data}')     # 打印偏置值
print(output_tensor)

 输出结果:

卷积核的权重tensor([[[ 0.0500,  0.1506, -0.2071]]])
偏置值tensor([-0.3645])
tensor([[[-0.6281, -0.6346, -0.6410, -0.6475,  0.5884]]],
       grad_fn=<SqueezeBackward1>)

 多运行两次,也可以看出每次的卷积核与偏置值并不相同。
第二次运行的结果:

卷积核的权重tensor([[[ 0.3540, -0.2518, -0.4792]]])
偏置值tensor([0.4238])
tensor([[[-0.7864, -1.1633, -1.5403, -1.9173,  0.5807]]],
       grad_fn=<SqueezeBackward1>)

 第三次运行的结果:

卷积核的权重tensor([[[-0.3216, -0.0135, -0.4280]]])
偏置值tensor([-0.0388])
tensor([[[-0.9082, -1.6713, -2.4343, -3.1973, -1.3925]]],
       grad_fn=<SqueezeBackward1>)

 总结:卷积核和偏置在不指定的情况下是随机数,在实际应用中,训练过程中可以通过优化算法自动调整。另外也可以手动指定卷积核和偏置,用来进行一些有目的的特征提取。
在下面的代码中,我们指定了卷积核和偏置:

import torch
import torch.nn as nn

# 定义一个1维Tensor,并调整其形状为(批次大小, 通道数, 序列长度)
input_tensor = torch.tensor([[[1.0, 2.0, 3.0, 4.0, 5.0]]])
# 定义一个简单的卷积层
conv_layer = nn.Conv1d(in_channels=1, out_channels=1, kernel_size=3, stride=1, padding=0, bias=True)

# 设置卷积核的权重
kernel = torch.tensor([[[1.0, 2.0, 3.0]]])
conv_layer.weight.data = kernel
# 设置卷积核的偏置
bias = torch.tensor([0.333])
conv_layer.bias.data = bias

# 应用卷积操作
output_tensor = conv_layer(input_tensor)
print(f'卷积核的权重:{conv_layer.weight.data}')
print(f'卷积核的偏置:{conv_layer.bias.data}')
print(f'卷积操作后的输出:{output_tensor}')

输出结果:

卷积核的权重:tensor([[[1., 2., 3.]]])
卷积核的偏置:tensor([0.3330])
卷积操作后的输出:tensor([[[14.3330, 20.3330, 26.3330]]], grad_fn=<SqueezeBackward1>)

从图像卷积的demo大致了解卷积的作用

新建一个图像文件,命名为demo_texture.png,保存在python脚本同文件夹下,放大后如下图 :

 这是一个20*20像素的图,每个方格是一个像素点,1:1显示是这个样子的:

 看得出,它是一个具有典型的均匀纹理特征的图片,在下面的代码中,我们通过定义一个卷积核来对它的纹理特征进行提取。

import torch
import torch.nn as nn
import torchvision.transforms as transforms
from PIL import Image

# 加载图像
image = Image.open('demo_texture.png')  # 替换为你的图像文件路径

# 转换为Tensor
transform = transforms.ToTensor()
image_tensor = transform(image).unsqueeze(0)  # 增加一个batch维度

# 定义一个卷积层
conv_layer = nn.Conv2d(in_channels=3, out_channels=1, kernel_size=3, stride=3, padding=0)

# 自定义卷积核
kernel = torch.tensor([
    [[0.0, 0.0, 0.0],
     [0.0, 0.3, 0.0],
     [0.0, 0.0, 0.0]],

    [[0.0, 0.0, 0.0],
     [0.0, 0.3, 0.0],
     [0.0, 0.0, 0.0]],

    [[0.0, 0.0, 0.0],
     [0.0, 0.3, 0.0],
     [0.0, 0.0, 0.0]]
], dtype=torch.float32)

# 重新调整权重形状
conv_layer.weight.data = kernel.view(1, 3, 3, 3)  # 用于卷积操作的卷积核形状应为 (out_channels, in_channels, kernel_height, kernel_width)

# 应用卷积
output = conv_layer(image_tensor)

# 转换Tensor到PIL图像
transform_to_pil = transforms.ToPILImage()

# 移除batch维度并转换
output_image = transform_to_pil(output.squeeze(0).detach().clamp(0, 1))
'''
在 PyTorch 中,detach () 函数用于从计算图中分离出一个 Tensor,返回一个新的 Tensor,这个新的 Tensor 
不再与计算图有任何关系,不再参与梯度计算。常用于将需要计算梯度的 Tensor 与不需要计算梯度的 Tensor 分离开来,
以便在反向传播时只对需要计算梯度的 Tensor 进行计算。
squeeze (0)” 通常指的是对某个数据结构或数组执行 “挤压” 操作,参数 “0” 可能表示沿着某个特定的维度进行操作。
更细致地说,“squeeze” 操作一般用于去除数组中大小为 1 的维度,而 “0” 可能表示要处理的是第一个维度。但具体的
含义还需要根据其所在的编程环境和上下文来确定。
“clamp (0, 1)” 通常表示一种限制或约束操作。它的意思是将某个值限定在 0 到 1 的范围内。具体来说,如果给定的
值小于 0 ,则返回 0 ;如果给定的值大于 1 ,则返回 1 ;如果给定的值在 0 到 1 之间,则返回该值本身。这种操作
常用于确保数值不会超出特定的范围,以保证程序的正确性和稳定性。
'''

# 显示卷积后的图像
output_image.show()

 运行结果的显示:

 放大之后的:

可以看到,卷积之后的图像尺寸只有6*6像素,但是保持了原图像的纹理特征。
通过定义不同形状和权重的卷积核就可以在卷积操作之后,提取不同类型的图像特征,比如纹理、轮廓等等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

深蓝海拓

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值