import paddle
import matplotlib.pyplot as plt
import paddle.nn as nn

class Conv2D(nn.Layer):
    def __init__(self, kernel_size, stride=1, padding=0, weight_attr=paddle.ParamAttr(initializer=nn.initializer.Constant(value=1.0))):
        super(Conv2D, self).__init__()
        self.weight = paddle.create_parameter(shape=[kernel_size, kernel_size], dtype='float32', attr=weight_attr)
        # 步长
        self.stride = stride
        # 零填充
        self.padding = padding

    def forward(self, X):
        # 零填充
        new_X = paddle.zeros([X.shape[0], X.shape[1] + 2 * self.padding, X.shape[2] + 2 * self.padding])
        new_X[:, self.padding:X.shape[1] + self.padding, self.padding:X.shape[2] + self.padding] = X
        u, v = self.weight.shape
        output_w = (new_X.shape[1] - u) // self.stride + 1
        output_h = (new_X.shape[2] - v) // self.stride + 1
        output = paddle.zeros([X.shape[0], output_w, output_h])
        for i in range(0, output.shape[1]):
            for j in range(0, output.shape[2]):
                output[:, i, j] = paddle.sum(new_X[:, self.stride * i:self.stride * i + u, self.stride * j:self.stride * j + v] * self.weight, axis=[1, 2])
        return output


inputs = paddle.randn(shape=[2, 8, 8])
conv2d_padding = Conv2D(kernel_size=8, stride=1, padding=1)
outputs = conv2d_padding(inputs)
print(f'When kernel_size=3, padding=1, stride=1, input\'s shape:{inputs.shape}, output\'s shape:{outputs.shape}')

conv2d_stride = Conv2D(kernel_size=3, stride=2, padding=1)
outputs = conv2d_stride(inputs)
print(f'When kernel_size=3, padding=1, stride=2, input\'s shape:{inputs.shape}, output\'s shape:{outputs.shape}')

# 使用卷积运算完成图像边缘检测任务
from PIL import Image
import numpy as np

# 读取图像
img = Image.open('D:\\Python\\Projects\\深度学习\\素材.JPG').resize((256, 256))

# 设置卷积核参数
w = np.array([[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]], dtype='float32')
conv = Conv2D(kernel_size=3, stride=1, padding=0, weight_attr=paddle.ParamAttr(initializer=nn.initializer.Assign(value=w)))

inputs = np.array(img).astype('float32')
# 图像转换成张量
inputs = paddle.to_tensor(inputs)
inputs = paddle.unsqueeze(inputs, axis=0)
outputs = conv(inputs)
outputs = outputs.numpy()

# 可视化结果
outputs = np.clip(outputs, 0, 1)
outputs = (outputs * 255).astype(np.uint8)

fig, axs = plt.subplots(1, 2, figsize=(8, 4))
axs[0].imshow(inputs[0])
axs[0].set_title('input image', fontsize=15)
axs[1].imshow(outputs[0], cmap='gray')
axs[1].set_title('output image', fontsize=15)
plt.show()

# 多通道卷积层实现
class Conv2D(nn.Layer):
    def __init__(self, in_channels, out_channels, kernel_size, stride=1, padding=0,
                 weight_attr=paddle.ParamAttr(initializer=nn.initializer.Constant(value=1.0)),
                 bias_attr=paddle.ParamAttr(initializer=nn.initializer.Constant(value=0.0))):
        super(Conv2D, self).__init__()
        # 创建卷积核
        self.weight = paddle.create_parameter(shape=[out_channels, in_channels, kernel_size, kernel_size], dtype='float32',
                                              attr=weight_attr)
        # 创建偏置
        self.bias = paddle.create_parameter(shape=[out_channels, 1], dtype='float32', attr=bias_attr)
        self.stride = stride
        self.padding = padding
        # 输入通道数
        self.in_channels = in_channels
        # 输出通道数
        self.out_channels = out_channels

    # 单通道特征图的卷积
    def single_forward(self, X, weight):
        # 零填充
        new_X = paddle.zeros([X.shape[0], X.shape[1] + 2 * self.padding, X.shape[2] + 2 * self.padding])
        new_X[:, self.padding:X.shape[1] + self.padding, self.padding:X.shape[2] + self.padding] = X
        u, v = weight.shape
        outputs_w = (new_X.shape[1] - u) // self.stride + 1
        outputs_h = (new_X.shape[2] - v) // self.stride + 1
        output = paddle.zeros([X.shape[0], outputs_w, outputs_h])
        for i in range(0, output.shape[1]):
            for j in range(0, output.shape[2]):
                output[:, i, j] = paddle.sum(new_X[:, self.stride * i:self.stride * i + u, self.stride * j:self.stride * j + v] * weight, axis=[1, 2])
        return output

    def multi2single_forward(self, input, weight, b):
        return paddle.sum(paddle.stack([self.single_forward(inputs[:i, :, :], weight[i]) for i in range(self.in_channels)], axis=1), axis=1) + b

    def multi2multi_forward(self, inputs, weights, bias):
        return paddle.stack([self.multi2single_forward(inputs, w, b) for w, b in zip(weights, bias)], axis=1)

    def forward(self, *inputs):
        return self.multi2multi_forward(inputs, self.weight, self.bias)


# 汇集层算子
class Pool2D(nn.Layer):
    def __init__(self, size=(2, 2), mode='max', stride=1):
        super(Pool2D, self).__init__()
        # 汇聚方式
        self.mode = mode
        self.h, self.w = size
        self.stride = stride

    def forward(self, x):
        output_w = (x.shape[2] - self.w) // self.stride + 1
        output_h = (x.shape[3] - self.h) // self.stride + 1
        output = paddle.zeros([x.shape[0], x.shape[1], output_w, output_h])

        # 汇聚
        for i in range(output.shape[2]):
            for j in range(output.shape[3]):
                # 最大汇聚
                if self.mode == 'max':
                    output[:, :, i, j] = paddle.max(x[:, :, self.stride * i:self.stride * i + self.w, self.stride * j:self.stride * j + self.h], axis=[2, 3])
                # 平均汇聚
                elif self.mode == 'avg':
                    output[:, :, i, j] = paddle.mean(x[:, :, self.stride * i:self.stride * i + self.w, self.stride * j:self.stride * j + self.h], axis=[2, 3])

        return output
Python卷积神经网络:深度学习中的卷积操作与代码实现

原文地址: https://www.cveoy.top/t/topic/b7A7 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录