CNN的实现(附代码)

article/2025/9/26 2:57:52

前言

前文已经单独实现了卷积层和池化层,现在来组合这些层,搭建进行手写数字识别的CNN。
这个简单的CNN网络构成如下。
在这里插入图片描述
网络的构成是“Convolution - ReLU - Pooling -Affine - ReLU - Affine - Softmax”,我们将它实现为名为SimpleConvNet的类。

该网络的参数
• input_dim―输入数据的维度:(通道,高,长)
• conv_param―卷积层的超参数(字典)。
字典的关键字如下:
filter_num―滤波器的数量
filter_size―滤波器的大小
stride―步幅
pad―填充
• hidden_size―隐藏层(全连接)的神经元数量
• output_size―输出层(全连接)的神经元数量
• weitght_int_std―初始化时权重的标准差

卷积层的超参数通过名为conv_param的字典传入。我们设想它会
像{‘filter_num’:30,‘filter_size’:5, ‘pad’:0, ‘stride’:1}。
这个CNN网络的初始化分为三个部分。

第一部分:取出初始化传入卷积层的超参数,并计算卷积层的输出大小

class SimpleConvNet:def __init__(self, input_dim=(1, 28, 28),conv_param={'filter_num':30, 'filter_size':5,'pad':0, 'stride':1},hidden_size=100, output_size=10, weight_init_std=0.01):filter_num = conv_param['filter_num']filter_size = conv_param['filter_size']filter_pad = conv_param['pad']filter_stride = conv_param['stride']input_size = input_dim[1]conv_output_size = (input_size - filter_size + 2*filter_pad) / filter_stride + 1pool_output_size = int(filter_num * (conv_output_size/2) *(conv_output_size/2))

第二部分:权重参数的初始化,包括第一层卷积层和两个全连接层的权重和偏置。分别为W1、b1、w2、b2、w3、b3

# 初始化权重
self.params = {}
self.params['W1'] = weight_init_std * np.random.randn(filter_num, input_dim[0], filter_size, filter_size)
self.params['b1'] = np.zeros(filter_num)
self.params['W2'] = weight_init_std * np.random.randn(pool_output_size, hidden_size)
self.params['b2'] = np.zeros(hidden_size)
self.params['W3'] = weight_init_std * np.random.randn(hidden_size, output_size)
self.params['b3'] = np.zeros(output_size)

第三步:生成对应的层,向有序字典(OrderedDict)的layers中添加层。只有最后的SoftmaxWithLoss层被添加到别的变量lastLayer

# 生成层
self.layers = OrderedDict()
self.layers['Conv1'] = Convolution(self.params['W1'], self.params['b1'],conv_param['stride'], conv_param['pad'])
self.layers['Relu1'] = Relu()
self.layers['Pool1'] = Pooling(pool_h=2, pool_w=2, stride=2)
self.layers['Affine1'] = Affine(self.params['W2'], self.params['b2'])
self.layers['Relu2'] = Relu()
self.layers['Affine2'] = Affine(self.params['W3'], self.params['b3'])self.last_layer = SoftmaxWithLoss()

以上就是SimpleConvNet的初始化中进行的处理。每一层的单独的具体实现已经在前面文中提到,为构建一个简单的CNN网络,每一层各司其职。

像这样进行初始化后,进行推理的predict方法和求损失函数的loss方法调用如下。

def predict(self, x):for layer in self.layers.values():x = layer.forward(x)return xdef loss(self, x, t):"""求损失函数参数x是输入数据、t是教师标签"""y = self.predict(x)return self.last_layer.forward(y, t)

predict方法从头开始依次调用已添加的层,并将结果传递给下一层。

接下来是基于误差反向传播求梯度

def gradient(self, x, t):"""求梯度(误差反向传播法)Parameters----------x : 输入数据t : 教师标签Returns-------具有各层的梯度的字典变量grads['W1']、grads['W2']、...是各层的权重grads['b1']、grads['b2']、...是各层的偏置"""# forwardself.loss(x, t)# backwarddout = 1dout = self.last_layer.backward(dout)layers = list(self.layers.values())layers.reverse()for layer in layers:dout = layer.backward(dout)# 设定grads = {}grads['W1'], grads['b1'] = self.layers['Conv1'].dW, self.layers['Conv1'].dbgrads['W2'], grads['b2'] = self.layers['Affine1'].dW, self.layers['Affine1'].dbgrads['W3'], grads['b3'] = self.layers['Affine2'].dW, self.layers['Affine2'].dbreturn grads

因为每一层的误差正向传播和反向传播已经在各层实现,也就是forward()和backward()方法,只需要依次调用每一层的方法即可,最后将每一层中各个权重参数的梯度保存到grads字典中。

simple_convnet类如下

import sys, os
sys.path.append(os.pardir)  # 为了导入父目录的文件而进行的设定
import pickle
import numpy as np
from collections import OrderedDict
from common.layers import *
from common.gradient import numerical_gradientclass SimpleConvNet:"""简单的ConvNetconv - relu - pool - affine - relu - affine - softmaxParameters----------input_size : 输入大小(MNIST的情况下为784)hidden_size_list : 隐藏层的神经元数量的列表(e.g. [100, 100, 100])output_size : 输出大小(MNIST的情况下为10)activation : 'relu' or 'sigmoid'weight_init_std : 指定权重的标准差(e.g. 0.01)指定'relu'或'he'的情况下设定“He的初始值”指定'sigmoid'或'xavier'的情况下设定“Xavier的初始值”"""def __init__(self, input_dim=(1, 28, 28), conv_param={'filter_num':30, 'filter_size':5, 'pad':0, 'stride':1},hidden_size=100, output_size=10, weight_init_std=0.01):filter_num = conv_param['filter_num']filter_size = conv_param['filter_size']filter_pad = conv_param['pad']filter_stride = conv_param['stride']input_size = input_dim[1]conv_output_size = (input_size - filter_size + 2*filter_pad) / filter_stride + 1pool_output_size = int(filter_num * (conv_output_size/2) * (conv_output_size/2))# 初始化权重self.params = {}self.params['W1'] = weight_init_std * \np.random.randn(filter_num, input_dim[0], filter_size, filter_size)self.params['b1'] = np.zeros(filter_num)self.params['W2'] = weight_init_std * \np.random.randn(pool_output_size, hidden_size)self.params['b2'] = np.zeros(hidden_size)self.params['W3'] = weight_init_std * \np.random.randn(hidden_size, output_size)self.params['b3'] = np.zeros(output_size)# 生成层self.layers = OrderedDict()self.layers['Conv1'] = Convolution(self.params['W1'], self.params['b1'],conv_param['stride'], conv_param['pad'])self.layers['Relu1'] = Relu()self.layers['Pool1'] = Pooling(pool_h=2, pool_w=2, stride=2)self.layers['Affine1'] = Affine(self.params['W2'], self.params['b2'])self.layers['Relu2'] = Relu()self.layers['Affine2'] = Affine(self.params['W3'], self.params['b3'])self.last_layer = SoftmaxWithLoss()def predict(self, x):for layer in self.layers.values():x = layer.forward(x)return xdef loss(self, x, t):"""求损失函数参数x是输入数据、t是教师标签"""y = self.predict(x)return self.last_layer.forward(y, t)def accuracy(self, x, t, batch_size=100):if t.ndim != 1 : t = np.argmax(t, axis=1)acc = 0.0for i in range(int(x.shape[0] / batch_size)):tx = x[i*batch_size:(i+1)*batch_size]tt = t[i*batch_size:(i+1)*batch_size]y = self.predict(tx)y = np.argmax(y, axis=1)acc += np.sum(y == tt) return acc / x.shape[0]def numerical_gradient(self, x, t):"""求梯度(数值微分)Parameters----------x : 输入数据t : 教师标签Returns-------具有各层的梯度的字典变量grads['W1']、grads['W2']、...是各层的权重grads['b1']、grads['b2']、...是各层的偏置"""loss_w = lambda w: self.loss(x, t)grads = {}for idx in (1, 2, 3):grads['W' + str(idx)] = numerical_gradient(loss_w, self.params['W' + str(idx)])grads['b' + str(idx)] = numerical_gradient(loss_w, self.params['b' + str(idx)])return gradsdef gradient(self, x, t):"""求梯度(误差反向传播法)Parameters----------x : 输入数据t : 教师标签Returns-------具有各层的梯度的字典变量grads['W1']、grads['W2']、...是各层的权重grads['b1']、grads['b2']、...是各层的偏置"""# forwardself.loss(x, t)# backwarddout = 1dout = self.last_layer.backward(dout)layers = list(self.layers.values())layers.reverse()for layer in layers:dout = layer.backward(dout)# 设定grads = {}grads['W1'], grads['b1'] = self.layers['Conv1'].dW, self.layers['Conv1'].dbgrads['W2'], grads['b2'] = self.layers['Affine1'].dW, self.layers['Affine1'].dbgrads['W3'], grads['b3'] = self.layers['Affine2'].dW, self.layers['Affine2'].dbreturn gradsdef save_params(self, file_name="params.pkl"):params = {}for key, val in self.params.items():params[key] = valwith open(file_name, 'wb') as f:pickle.dump(params, f)def load_params(self, file_name="params.pkl"):with open(file_name, 'rb') as f:params = pickle.load(f)for key, val in params.items():self.params[key] = valfor i, key in enumerate(['Conv1', 'Affine1', 'Affine2']):self.layers[key].W = self.params['W' + str(i+1)]self.layers[key].b = self.params['b' + str(i+1)]

参考

《深度学习入门:基于Python的理论与实现 》斋藤康毅


http://chatgpt.dhexx.cn/article/Cy6XxiKZ.shtml

相关文章

CNN卷积网络简介

CNN卷积网络 CNN卷积网络的结构 输入层: 输入层是3232 RGB图像。 注:有必要计算每一层输出的图片大小。 卷积层: 卷积层的核心在于卷积核与激活函数。   卷积层最主要的作用是寻找与卷积核匹配的特征,因为与卷积核符合(卷积核…

CNN的通俗理解

Agenda 1 卷积神经网络Convolutional Neural Networks,CNN1.1 前言1.2 图像转化成矩阵1.3 卷积核1.4 特征图feature map1.5 激活函数1.6 池化1.7 训练 1 卷积神经网络Convolutional Neural Networks,CNN 1.1 前言 卷积神经网络是针对图像的深度学习框架。 1.2 图像转化成矩阵…

CNN网络详解

分割线----------------------------------   这里更新过一次,在朋友的提醒下,我发现这份代码不是很容易懂。我使用了Pytorch给的官方demo重新实现了LeNet,并做出了详细解释,如果理解下面代码有问题,可以先看我的这篇…

卷积神经网络(CNN)基本概念

一、卷积神经网络基本概念 卷积神经网络包含了一个由卷积层和子采样层构成的特征抽取器。在卷积神经网络的卷积层中,一个神经元只与部分邻层神经元相连接。在CNN的一个卷积层中,通常包含若干个特征平面,每个特征平面都由一些矩形排列的神经元…

CNN简单介绍及基础知识

文章目录 一)卷积神经网络历史沿革 二)CNN简单介绍 三)CNN相关基础知识 前言 在过去的几年里,卷积神经网络(CNN)引起了人们的广泛关注,尤其是因为它彻底改变了计算机视觉领域,它是近年来深度学习能在计算机…

一文读懂目标检测:R-CNN、Fast R-CNN、Faster R-CNN、YOLO、SSD

一文读懂目标检测:R-CNN、Fast R-CNN、Faster R-CNN、YOLO、SSD 前言 之前我所在的公司七月在线开设的深度学习等一系列课程经常会讲目标检测,包括R-CNN、Fast R-CNN、Faster R-CNN,但一直没有比较好的机会深入(但当你对目标检测…

理解 CNN

理解 CNN 注意:下面提到的图像指位图 目录 理解 CNNCNN人类的视觉原理几个关键层卷积层(fliter、kernel)池化层 (pooling) 激活层(activate)全连接层(Linear) pytorch实现TextCNN卷积传播图解不同视角看CNN 参考 CNN 卷积神经网络-CNN 最擅长的就是图片的处理。它…

【深度学习】CNN算法

一.定义: 卷积神经网络(CNN),是一类包含卷积计算且具有深度结构前馈神经网络,是深度学习(deep learning)的代表算法之一。 卷积神经网络具有表征能力,能够按其阶层结构对输入信息进…

Python CNN卷积神经网络实例讲解,CNN实战,CNN代码实例,超实用

一、CNN简介 1. 神经网络基础 输入层(Input layer),众多神经元(Neuron)接受大量非线形输入讯息。输入的讯息称为输入向量。 输出层(Output layer),讯息在神经元链接中传输、分析、权…

CNN(卷积神经网络)详解

Why CNN 首先回答这样一个问题,为什么我们要学CNN,或者说CNN为什么在很多领域收获成功?还是先拿MNIST来当例子说。MNIST数据结构不清楚的话自行百度。。 我自己实验用两个hidden layer的DNN(全连接深度神经网络)在MNIST上也能取得不错的成绩…

CNN(Convolutional Neural Network)

CNN的基本结构 图中是一个图形识别的CNN模型。可以看出最左边的船的图像就是我们的输入层,计算机理解为输入若干个矩阵,这点和DNN基本相同。 接着是卷积层(Convolution Layer),这个是CNN特有的。卷积层的激活函数使用的是ReLU。我…

CNN(卷积神经网络)是什么?(转)

 作者:机器之心 链接:https://www.zhihu.com/question/52668301/answer/131573702 来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 卷积神经网络,听起来…

CNN

卷积神经网络(Convolutional Neural Networks)是一种深度学习模型或类似于人工神经网络的多层感知器,常用来分析视觉图像。CNN在图像分类数据集上有非常突出的表现。 DNN与CNN 下图为DNN: 下图为CNN: 虽然两张图的结构…

CNN卷积神经网络(图解CNN)

文章目录 什么是卷积神经网络:1)网络结构2)局部感受野与权值共享3)卷积层、下采样层、全连接层卷积神经网络相比一般神经网络在图像理解中的优点:边缘检测卷积运算卷积层卷积后维度公式及运算示例 Padding填充Valid卷积…

CNN-卷积神经网络

一、基本的神经网络结构 神经网络其实就是按照一定规则连接起来的多个神经元,输入向量的维度和输入层(Input Layer)神经元个数相同,分类问题的类别个数决定输入层(Output Lazyer)的神经元个数。第N层的神经…

CNN是个啥?

阅读须知 本文主要意义是为了方便对CNN有个最直观的理解,知道这个玩意到底是干嘛的。文章本体是UP自己自学深度学习这块的时候做的笔记,内容均为网上收录。发在这里的原因是因为,也许有很多像UP一样不理解了就完全学不了的人存在&#xff0c…

(太长太全面了)CNN超详细介绍

原文链接:https://blog.csdn.net/jiaoyangwm/article/details/80011656 文章目录 1、卷积神经网络的概念2、 发展过程3、如何利用CNN实现图像识别的任务4、CNN的特征5、CNN的求解6、卷积神经网络注意事项7、CNN发展综合介绍8、LeNet-5结构分析9、AlexNet10、ZFNet10…

深度学习——卷积神经网络(CNN)简介

卷积神经网络简介 文章目录 卷积神经网络简介前言一.如何理解卷积1.1什么是卷积1.2 为什么要卷积 二.神经网络的结构三.卷积层四.池化层五.全连接层六.数据训练七.常见的卷积神经网络1. LeNet2 AlexNet3. VGG net4. ResNet 前言 卷积神经网络(Convolutional Neural…

CNN卷积神经网络 的学习记录一

1. 概述 卷积神经网络的特点:一方面它的神经元间的连接是非全连接的, 另一方面同一层中某些神经元之间的连接的权重是共享的(即相同的)。 上图左:图像有1000*1000个像素,有10^6个隐层神经元,进行…

CNN是什么意思?它与传统神经网络有什么不同?

CNN代表卷积神经网络(Convolutional Neural Network)。它是一种专门用于处理具有网格结构数据的神经网络模型,尤其在图像识别和计算机视觉任务中表现出色。CNN的设计灵感来自于生物视觉系统对视觉信息的处理方式。 与传统神经网络相比&#x…