【复现】尝试使用numpy对卷积神经网络中各经典结构进行改写复现

简介: 【复现】尝试使用numpy对卷积神经网络中各经典结构进行改写复现

前言

  numpy作为Python中最常用的科学计算库之一,也被广泛应用于卷积神经网络中的各个组件。本篇博客将介绍如何使用numpy完成卷积神经网络中的各个组件,包括卷积层、池化层、全连接层等,帮助读者更好地理解卷积神经网络的实现原理,同时也能够更加熟练地使用numpy进行深度学习相关的编程。

卷积层

  使用numpy写出卷积层函数需要考虑多个方面,包括输入数据的格式、卷积核的设置、卷积的步长和填充、矩阵乘法的实现以及梯度的计算等

  1. 输入数据的维度和格式:卷积层的输入数据通常是一个四维数组,分别表示样本数、通道数、高度和宽度。因此,在编写卷积层函数时,需要考虑输入数据的维度和格式,以保证函数能够正确地处理数据。
  2. 卷积核的维度和格式:卷积核也是一个四维数组,分别表示输入通道数、输出通道数、卷积核高度和卷积核宽度。在编写卷积层函数时,需要考虑卷积核的维度和格式,以保证函数能够正确地卷积输入数据。
  3. 卷积的步长和填充:卷积层通常会用步长和填充来控制输出数据的尺寸。在编写卷积层函数时,需要考虑步长和填充的设置,以保证函数能够正确地卷积输入数据并输出正确的尺寸。
  4. 矩阵乘法的实现:卷积操作可以看作是一种矩阵乘法操作,因此在编写卷积层函数时,需要考虑如何使用numpy实现高效的矩阵乘法操作,以提高函数的运行效率。
  5. 梯度的计算:在卷积神经网络中,梯度的计算是非常重要的,它可以用来更新卷积核和输入数据的参数。在编写卷积层函数时,需要考虑如何计算梯度,并将梯度传递给前一层的神经元,以实现反向传播算法。

参数说明:

x: 输入数据,shape为(batch_size, in_channels, height, width)

w: 卷积核,shape为(out_channels, in_channels, kernel_height, kernel_width)

b: 偏置,shape为(out_channels,)

stride: 步长,默认为1

padding: 填充,默认为0\

out: 卷积结果,shape为(batch_size, out_channels, out_height, out_width)

ini

复制代码

import numpy as np
    def conv2d(x, w, b, stride=1, padding=0):
        batch_size, in_channels, height, width = x.shape
        out_channels, _, kernel_height, kernel_width = w.shape
        # 计算输出特征图的尺寸
        out_height = (height + 2 * padding - kernel_height) // stride + 1
        out_width = (width + 2 * padding - kernel_width) // stride + 1
        # 对输入数据进行填充
        x_pad = np.pad(x, ((0, 0), (0, 0), (padding, padding), (padding, padding)), mode='constant')
        # 初始化输出特征图
        out = np.zeros((batch_size, out_channels, out_height, out_width))
        # 进行卷积操作
        for i in range(out_height):
            for j in range(out_width):
                for k in range(out_channels):
                    out[:, k, i, j] = np.sum(x_pad[:, :, i*stride:i*stride+kernel_height, j*stride:j*stride+kernel_width] * w[k, :, :, :], axis=(1, 2, 3)) + b[k]
        return out

使用示例

ini

复制代码

# 构造输入数据
x = np.random.randn(1, 3, 640, 640)
# 构造卷积核和偏置
w = np.random.randn(64, 3, 3, 3)
b = np.random.randn(64)
# 进行卷积操作
out = conv2d(x, w, b, stride=1, padding=1)
# 打印输出特征图的尺寸
print(out.shape)

池化层

  使用numpy写出池化层函数需要考虑多个方面,包括输入数据的格式、池化的类型和大小、池化的步长和填充、矩阵乘法的实现以及梯度的计算。

  1. 输入数据的维度和格式:池化层的输入数据通常是一个四维数组,分别表示样本数、通道数、高度和宽度。因此,在编写池化层函数时,需要考虑输入数据的维度和格式,以保证函数能够正确地处理数据。
  2. 池化的类型和大小:池化层通常有两种类型,即最大池化和平均池化,同时还需要设置池化的大小。在编写池化层函数时,需要考虑池化的类型和大小的设置,以保证函数能够正确地池化输入数据。
  3. 池化的步长和填充:池化层通常会用步长和填充来控制输出数据的尺寸。在编写池化层函数时,需要考虑步长和填充的设置,以保证函数能够正确地池化输入数据并输出正确的尺寸。
  4. 矩阵乘法的实现:池化操作可以看作是一种矩阵乘法操作,因此在编写池化层函数时,需要考虑如何使用numpy实现高效的矩阵乘法操作,以提高函数的运行效率。
  5. 梯度的计算:在卷积神经网络中,梯度的计算是非常重要的,它可以用来更新输入数据的参数。在编写池化层函数时,需要考虑如何计算梯度,并将梯度传递给前一层的神经元,以实现反向传播算法。

ini

复制代码

import numpy as np
    def max_pooling(input_data, pool_size, strides):
        batch_size, in_channels, in_height, in_width = input_data.shape
        pool_height, pool_width = pool_size
        stride_height, stride_width = strides
        out_height = int((in_height - pool_height) / stride_height + 1)
        out_width = int((in_width - pool_width) / stride_width + 1)
        output_data = np.zeros((batch_size, in_channels, out_height, out_width))
        for i in range(out_height):
            for j in range(out_width):
                output_data[:, :, i, j] = np.max(
                    input_data[:, :, i * stride_height:i * stride_height + pool_height,
                               j * stride_width:j * stride_width + pool_width], axis=(2, 3))
        return output_data

scss

复制代码

input_data = np.random.randn(1, 3, 640, 640)
    pool_size = (2, 2)
    strides = (2, 2)
    output_data = max_pooling(input_data, pool_size, strides)
    print("input_data:\n", input_data.shape)
    print("output_data:\n", output_data.shape)

image.png

  这个函数接受三个参数:输入数据、池化窗口大小和步幅。 输入数据的形状为(batch_size, in_channels, in_height, in_width),其中batch_size表示批次大小,in_channels表示输入数据的通道数,in_heightin_width分别表示输入数据的高度和宽度。 池化窗口大小为(pool_height, pool_width),步幅为(stride_height, stride_width)。这个函数通过双重循环遍历每个池化窗口,然后在这个窗口内取最大值作为输出值。

Dropout层

Dropout层具有一定的随机性:

Dropout层的主要作用是随机删除一部分神经元,因此在实现时需要使用随机数生成器产生一个0-1之间的随机数矩阵,然后根据设定的概率阈值(如0.5)来判断哪些神经元需要被删除。

训练和测试模式:

在训练和测试两个阶段,Dropout层的行为是不同的。在训练阶段,Dropout层会删除一部分神经元;而在测试阶段,Dropout层不会删除神经元,而是将所有神经元的权重乘以概率阈值(如0.5),以保持期望输出不变。因此,在实现时需要添加一个参数来表示当前是训练还是测试模式,并针对不同模式进行不同的计算。

归一化:

在删除一部分神经元后,Dropout层会使得剩余神经元的输出值变大,因此需要对输出值进行归一化。一种简单的方法是将输出值除以概率阈值(如0.5),以保持期望输出不变。

反向传播:

在反向传播过程中,Dropout层需要将输出值乘以一个掩码矩阵(即随机删除的神经元对应位置为0,未删除的神经元对应位置为1),以保留未删除神经元的梯度信息。因此,在实现时需要注意掩码矩阵的生成和使用。

参数管理:

Dropout层没有可训练参数,因此在实现时不需要考虑参数初始化和更新的问题。

ini

复制代码

import numpy as np
    def dropout(x, p):
        # 其中,x是输入的矩阵,p是保留概率
        mask = np.random.binomial(1, 1-p, size=x.shape) / (1-p)
        return x * mask
    # 生成一个的矩阵
    x = np.random.rand(1, 3, 640, 640)
    # 使用dropout函数保留概率为0.5
    y = dropout(x, 0.5)

scss

复制代码

# 输出x和y的值
    print("x:")
    print(x.shape)
    print("y:")
    print(y.shape)

image.png

全连接层

输入输出维度:

全连接层的输入和输出都是二维矩阵,其中输入矩阵的第一维表示样本数,第二维表示特征数;输出矩阵的第一维表示样本数,第二维表示输出节点数。在实现时需要确保输入输出矩阵的维度正确。

权重和偏置:

全连接层的核心是权重矩阵和偏置向量。在实现时需要使用随机数生成器初始化权重矩阵和偏置向量,并在反向传播过程中更新它们的值。

前向传播:

全连接层的前向传播过程是将输入矩阵和权重矩阵相乘,再加上偏置向量,最后通过激活函数得到输出矩阵。在实现时需要注意矩阵乘法的维度匹配和激活函数的选择。

反向传播:

全连接层的反向传播过程是根据损失函数对权重矩阵和偏置向量进行梯度更新。在实现时需要注意梯度的计算和矩阵乘法的转置。同时,为了避免梯度消失或爆炸,可以使用梯度裁剪等方法进行优化。

批量处理:

在实际使用中,一般会采用批量处理的方式进行训练。因此,在实现时需要注意批量大小的设置,以及在前向传播和反向传播过程中对批量数据进行处理。

参数管理:

全连接层的参数包括权重矩阵和偏置向量,需要进行初始化和更新。在实现时需要注意参数的维度和存储方式。

python

复制代码

import numpy as np
    class FullyConnectedLayer:
        def __init__(self, input_size, output_size):
            self.W = np.random.randn(input_size, output_size) * 0.01
            self.b = np.zeros((1, output_size))
            self.input = None
        def forward(self, x):
            self.input = x
            output = np.dot(x, self.W) + self.b
            return output
        def backward(self, grad_output, learning_rate):
            grad_input = np.dot(grad_output, self.W.T)
            grad_W = np.dot(self.input.T, grad_output)
            grad_b = np.sum(grad_output, axis=0, keepdims=True)
            self.W -= learning_rate * grad_W
            self.b -= learning_rate * grad_b
            return grad_input

ini

复制代码

# 生成随机输入
x = np.random.randn(10, 5)
# 创建全连接层
fc_layer = FullyConnectedLayer(5, 3)
# 进行前向传播
output = fc_layer.forward(x)
# 打印输出的形状
print("output.shape:", output.shape)
# 进行反向传播
grad_output = np.random.randn(10, 3)
grad_input = fc_layer.backward(grad_output, 0.01)
# 打印反向传播的输出形状
print("grad_input.shape", grad_input.shape)

image.png

BN层

  1. 计算均值和方差:BN层的主要作用是对每个特征进行均值和方差归一化,以使得每个特征在不同样本中具有相似的分布。在实现时需要计算每个特征的均值和方差,可以使用numpy的mean和var函数进行计算。
  2. 归一化:根据计算得到的均值和方差,可以对每个特征进行归一化处理,以使得每个特征的均值为0,方差为1。在实现时需要注意除以方差时需要加上一个很小的数(如1e-8)以避免除以0的情况。
  3. 缩放和平移:为了保留每个特征的表达能力,BN层还需要对归一化后的结果进行缩放和平移。具体来说,对于每个特征,需要学习一个缩放因子和一个平移因子,以使得归一化后的结果可以任意平移和缩放。在实现时需要使用随机数生成器初始化缩放和平移因子,并在反向传播过程中更新它们的值。
  4. 反向传播:在反向传播过程中,BN层需要计算梯度,并根据梯度更新缩放和平移因子。在实现时需要注意梯度的计算和矩阵乘法的转置。同时,为了避免梯度消失或爆炸,可以使用梯度裁剪等方法进行优化。
  5. 训练和测试模式:在训练和测试两个阶段,BN层的行为是不同的。在训练阶段,BN层会根据当前批量数据计算均值和方差,并使用它们对每个特征进行归一化;而在测试阶段,BN层需要使用之前计算得到的整个数据集的均值和方差对每个特征进行归一化。因此,在实现时需要添加一个参数来表示当前是训练还是测试模式,并针对不同模式进行不同的计算。
  6. 参数管理:BN层的参数包括缩放因子和平移因子,需要进行初始化和更新。在实现时需要注意参数的维度和存储方式。

ini

复制代码

import numpy as np
    import matplotlib.pyplot as plt
    def batch_norm(x, gamma, beta, eps=1e-5):
        N, C, H, W = x.shape
        mu = np.mean(x, axis=(0, 2, 3), keepdims=True)
        var = np.var(x, axis=(0, 2, 3), keepdims=True)
        x_norm = (x - mu) / np.sqrt(var + eps)
        out = gamma.reshape(1, C, 1, 1) * x_norm + beta.reshape(1, C, 1, 1)
        cache = (x, x_norm, mu, var, gamma, beta, eps)
        return out, cache

ini

复制代码

# 随机生成一个四维数据集
    np.random.seed(0)
    x = np.random.randn(1, 3, 640, 640)
    # 对数据进行BN层处理
    gamma = np.ones(3)
    beta = np.zeros(3)
    x_norm, _ = batch_norm(x, gamma, beta)
    # 绘制归一化前后的数据分布图
    fig, axs = plt.subplots(2, 1, figsize=(8, 6))
    axs[0].hist(np.sum(x, axis=(1, 2, 3)), bins=50)
    axs[0].set_title("Before BN")
    axs[1].hist(np.sum(x_norm, axis=(1, 2, 3)), bins=50)
    axs[1].set_title("After BN")
    plt.show()

image.png


相关文章
|
11天前
|
机器学习/深度学习 人工智能 自然语言处理
深度学习中的卷积神经网络(CNN)及其应用
【9月更文挑战第24天】本文将深入探讨深度学习中的一种重要模型——卷积神经网络(CNN)。我们将通过简单的代码示例,了解CNN的工作原理和应用场景。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的信息。
36 1
|
16天前
|
机器学习/深度学习 人工智能 算法
植物病害识别系统Python+卷积神经网络算法+图像识别+人工智能项目+深度学习项目+计算机课设项目+Django网页界面
植物病害识别系统。本系统使用Python作为主要编程语言,通过收集水稻常见的四种叶片病害图片('细菌性叶枯病', '稻瘟病', '褐斑病', '稻瘟条纹病毒病')作为后面模型训练用到的数据集。然后使用TensorFlow搭建卷积神经网络算法模型,并进行多轮迭代训练,最后得到一个识别精度较高的算法模型,然后将其保存为h5格式的本地模型文件。再使用Django搭建Web网页平台操作界面,实现用户上传一张测试图片识别其名称。
66 21
植物病害识别系统Python+卷积神经网络算法+图像识别+人工智能项目+深度学习项目+计算机课设项目+Django网页界面
|
15天前
|
机器学习/深度学习 算法 TensorFlow
交通标志识别系统Python+卷积神经网络算法+深度学习人工智能+TensorFlow模型训练+计算机课设项目+Django网页界面
交通标志识别系统。本系统使用Python作为主要编程语言,在交通标志图像识别功能实现中,基于TensorFlow搭建卷积神经网络算法模型,通过对收集到的58种常见的交通标志图像作为数据集,进行迭代训练最后得到一个识别精度较高的模型文件,然后保存为本地的h5格式文件。再使用Django开发Web网页端操作界面,实现用户上传一张交通标志图片,识别其名称。
44 6
交通标志识别系统Python+卷积神经网络算法+深度学习人工智能+TensorFlow模型训练+计算机课设项目+Django网页界面
|
11天前
|
机器学习/深度学习 人工智能 算法
【新闻文本分类识别系统】Python+卷积神经网络算法+人工智能+深度学习+计算机毕设项目+Django网页界面平台
文本分类识别系统。本系统使用Python作为主要开发语言,首先收集了10种中文文本数据集("体育类", "财经类", "房产类", "家居类", "教育类", "科技类", "时尚类", "时政类", "游戏类", "娱乐类"),然后基于TensorFlow搭建CNN卷积神经网络算法模型。通过对数据集进行多轮迭代训练,最后得到一个识别精度较高的模型,并保存为本地的h5格式。然后使用Django开发Web网页端操作界面,实现用户上传一段文本识别其所属的类别。
24 1
【新闻文本分类识别系统】Python+卷积神经网络算法+人工智能+深度学习+计算机毕设项目+Django网页界面平台
|
4天前
|
机器学习/深度学习 人工智能 算法
深入理解卷积神经网络:从理论到实践
【9月更文挑战第31天】在深度学习的众多模型之中,卷积神经网络(CNN)以其在图像处理领域的出色表现而闻名。本文将通过浅显易懂的语言和直观的比喻,带领读者了解CNN的核心原理和结构,并通过一个简化的代码示例,展示如何实现一个简单的CNN模型。我们将从CNN的基本组成出发,逐步深入到其在现实世界中的应用,最后探讨其未来的可能性。文章旨在为初学者提供一个清晰的CNN入门指南,同时为有经验的开发者提供一些深入思考的视角。
|
4天前
|
机器学习/深度学习 人工智能 算法框架/工具
深度学习中的卷积神经网络(CNN)及其在图像识别中的应用
【9月更文挑战第31天】本文旨在通过浅显易懂的语言和直观的比喻,为初学者揭开深度学习中卷积神经网络(CNN)的神秘面纱。我们将从CNN的基本原理出发,逐步深入到其在图像识别领域的实际应用,并通过一个简单的代码示例,展示如何利用CNN进行图像分类。无论你是编程新手还是深度学习的初学者,这篇文章都将为你打开一扇通往人工智能世界的大门。
|
5天前
|
机器学习/深度学习 人工智能 自然语言处理
深度学习中的卷积神经网络(CNN)入门与实践
【8月更文挑战第62天】本文以浅显易懂的方式介绍了深度学习领域中的核心技术之一——卷积神经网络(CNN)。文章通过生动的比喻和直观的图示,逐步揭示了CNN的工作原理和应用场景。同时,结合具体的代码示例,引导读者从零开始构建一个简单的CNN模型,实现对图像数据的分类任务。无论你是深度学习的初学者还是希望巩固理解的开发者,这篇文章都将为你打开一扇通往深度学习世界的大门。
|
11天前
|
机器学习/深度学习 人工智能 算法
【果蔬识别系统】Python+卷积神经网络算法+人工智能+深度学习+计算机毕设项目+Django网页界面平台
【果蔬识别系统】Python+卷积神经网络算法+人工智能+深度学习+计算机毕设项目+Django网页界面平台。果蔬识别系统,本系统使用Python作为主要开发语言,通过收集了12种常见的水果和蔬菜('土豆', '圣女果', '大白菜', '大葱', '梨', '胡萝卜', '芒果', '苹果', '西红柿', '韭菜', '香蕉', '黄瓜'),然后基于TensorFlow库搭建CNN卷积神经网络算法模型,然后对数据集进行训练,最后得到一个识别精度较高的算法模型,然后将其保存为h5格式的本地文件方便后期调用。再使用Django框架搭建Web网页平台操作界面,实现用户上传一张果蔬图片识别其名称。
31 0
【果蔬识别系统】Python+卷积神经网络算法+人工智能+深度学习+计算机毕设项目+Django网页界面平台
|
15天前
|
机器学习/深度学习 自动驾驶 TensorFlow
深入理解卷积神经网络(CNN)在图像识别中的应用
【9月更文挑战第20天】本文旨在通过直观的解释和代码示例,向初学者介绍卷积神经网络(CNN)的基本概念及其在图像识别领域的应用。文章将首先解释什么是CNN以及它如何工作,然后通过一个简单的Python代码示例展示如何构建一个基本的CNN模型。最后,我们将讨论CNN在现实世界问题中的潜在应用,并探讨其面临的挑战和发展方向。
36 2
|
15天前
|
机器学习/深度学习 人工智能 算法
深入浅出卷积神经网络(CNN)
【9月更文挑战第20天】在人工智能的璀璨星河中,卷积神经网络(CNN)如同一颗耀眼的星辰,以其独特的魅力照亮了图像处理的天空。本文将带你遨游CNN的宇宙,从其诞生之初的微弱光芒,到成为深度学习领域的超级巨星,我们将一同探索它的结构奥秘、工作原理以及在实际场景中的惊艳应用。你将发现,CNN不仅仅是一段段代码和算法的堆砌,它更是一种让机器“看”懂世界的强大工具。让我们扣好安全带,一起深入CNN的世界,体验技术与创新交织的精彩旅程。
下一篇
无影云桌面