python基础代码库-CNN详解-基于python基础库实现的简单CNN
CNN,即卷积神经网络,主要用于图像识别,分类。由输入层,卷积层,池化层,全连接层(Affline层),Softmax层叠加而成。卷积神经网络中还有一个非常重要的结构:过滤器,它作用于层与层之间(卷积层与池化层),决定了怎样对数据进行卷积和池化。下面先直观理解下卷积和池化
二维卷积
即滤波器的每个格子与滤波器选中数据的格子相乘
三维卷积
三维数据的话,滤波器的也是三维。同时对每个维度进行卷积,最后将每个维度的卷积结果相加,输出二维。
池化
池化分为最大池化层与平均池化层。最大池化层对滤波器选中的数据取最大值,平均池化层对滤波器选中的数据求平均值。一般使用最大池化层。池化层是单独作用于每个维度,若是三维数据,即对每个维度上进行最大/平均操作,输入结果也是三维。
卷积用于提取高层次特征,池化用于缩小参数。一般为一层卷积加一层池化反复叠加或多层卷积加一层池化。
全连接层用于卷积池化后,对数据列化然后经过一两层全连接层,得出结果。
softmax用于最后的分类
好了,知道卷积池化,下面就来实现最简单的一个卷积网络:
灵魂画笔。(*^__^*) relu为激活函数,FC即全连接层,也即Affine层
CNN实现手写数字识别
Package
import sys ,os
import numpy as np
import matplotlib.pyplot as plt
import tensorflow as tf #只是用来加载mnist数据集
from PIL import Image
import pandas as pd
import math
加载MNIST数据集
def one_hot_label(y):
one_hot_label = np.zeros((y.shape[0],10))
y = y.reshape(y.shape[0])
one_hot_label[range(y.shape[0]),y] = 1
return one_hot_label
# #(训练图像,训练标签),(测试图像,测试标签)
# # mnist的图像均为28*28尺寸的数据,通道为1
(x_train_origin,t_train_origin),(x_test_origin,t_test_origin) = tf.keras.datasets.mnist.load_data()
X_train = x_train_origin/255.0
X_test = x_test_origin/255.0
m,h,w = x_train_origin.shape
X_train = X_train.reshape((m,1,h,w))
y_train = one_hot_label(t_train_origin)
m,h,w = x_test_origin.shape
X_test = X_test.reshape((m,1,h,w))
y_test = one_hot_label(t_test_origin)
print("shape of x_train is :"+repr(X_train.shape))
print("shape of t_train is :"+repr(y_train.shape))
print("shape of x_test is :"+repr(X_test.shape))
print("shape of t_test is :"+repr(y_test.shape))
shape of x_train is :(60000, 1, 28, 28)
shape of t_train is :(60000, 10)
shape of x_test is :(10000, 1, 28, 28)
shape of t_test is :(10000, 10)
显示图像
index = 0
plt.imshow(X_train[index].reshape((28,28)),cmap = plt.cm.gray)
print("y is:"+str(np.argmax(y_train[index])))
y is:5
output_7_1.png
激活函数
def relu(input_X):
"""
Arguments:
input_X -- a numpy array
Return :
A: a numpy array. let each elements in array all greater or equal 0
"""
A = np.where(input_X < 0 ,0,input_X)
return A
def softmax(input_X):
"""
Arguments:
input_X -- a numpy array
Return :
A: a numpy array same shape with input_X
"""
exp_a = np.exp(input_X)
sum_exp_a = np.sum(exp_a,axis=1)
sum_exp_a = sum_exp_a.reshape(input_X.shape[0],-1)
ret = exp_a/sum_exp_a
# print(ret)
return ret
损失函数
def cross_entropy_error(labels,logits):
return -np.sum(labels*np.log(logits))
卷积层
class Convolution:
def __init__(self,W,fb,stride = 1,pad = 0):
"""
W-- 滤波器权重,shape为(FN,NC,FH,FW),FN 为滤波器的个数
fb -- 滤波器的偏置,shape 为(1,FN)
stride -- 步长
pad -- 填充个数
"""
self.W = W
self.fb = fb
self.stride = stride
self.pad = pad
self.col_X = None
self.X = None
self.col_W = None
self.dW = None
self.db = None
self.out_shape = None
# self.out = None
def forward (self ,input_X):
"""
input_X-- shape为(m,nc,height,width)
"""
self.X = input_X
FN,NC,FH,FW = self.W.shape
m,input_nc, input_h,input_w = self.X.shape
#先计算输出的height和widt
out_h = int((input_h+2*self.pad-FH)/self.stride + 1)
out_w = int((input_w+2*self.pad-FW)/self.stride + 1)
#将输入数据展开成二维数组,shape为(m*out_h*out_w,FH*FW*C)
self.col_X = col_X = im2col2(self.X,FH,FW,self.stride,self.pad)
#将滤波器一个个按列展开(FH*FW*C,FN)
self.col_W = col_W = self.W.reshape(FN,-1).T
out = np.dot(col_X,col_W)+self.fb
out = out.T
out = out.reshape(m,FN,out_h,out_w)
self.out_shape = out.shape
return out
def backward(self, dz,learning_rate):
#print("==== Conv backbward ==== ")
assert(dz.shape == self.out_shape)
FN,NC,FH,FW = self.W.shape
o_FN,o_NC,o_FH,o_FW = self.out_shape
col_dz = dz.reshape(o_NC,-1)
col_dz = col_dz.T
self.dW = np.dot(self.col_X.T,col_dz) #shape is (FH*FW*C,FN)
self.db = np.sum(col_dz,axis=0,keepdims=True)
self.dW = self.dW.T.reshape(self.W.shape)
self.db = self.db.reshape(self.fb.shape)
d_col_x = np.dot(col_dz,self.col_W.T) #shape is (m*out_h*out_w,FH,FW*C)
dx = col2im2(d_col_x,self.X.shape,FH,FW,stride=1)
assert(dx.shape == self.X.shape)
#更新W和b
self.W = self.W - learning_rate*self.dW
self.fb = self.fb -learning_rate*self.db
return dx
池化层
class Pooling:
def __init__(self,pool_h,pool_w,stride = 1,pad = 0):
self.pool_h = pool_h
self.pool_w = pool_w
self.stride = stride
self.pad = pad
self.X = None
self.arg_max = None
def forward ( self,input_X) :
"""
前向传播
input_X-- shape为(m,nc,height,width)
"""
self.X = input_X
N , C, H, W = input_X.shape
out_h = int(1+(H-self.pool_h)/self.stride)
out_w = int(1+(W-self.pool_w)/self.stride)
#展开
col = im2col2(input_X,self.pool_h,self.pool_w,self.stride,self.pad)
col = col.reshape(-1,self.pool_h*self.pool_w)
arg_max = np.argmax(col,axis=1)
#最大值
out = np.max(col,axis=1)
out =out.T.reshape(N,C,out_h,out_w)
self.arg_max = arg_max
return out
def backward(self ,dz):
"""
反向传播
Arguments:
dz-- out的导数,shape与out 一致
Return:
返回前向传播是的input_X的导数
"""
pool_size = self.pool_h*self.pool_w
dmax = np.zeros((dz.size,pool_size))
dmax[np.arange(self.arg_max.size),self.arg_max.flatten()] = dz.flatten()
dx = col2im2(dmax,out_shape=self.X.shape,fh=self.pool_h,fw=self.pool_w,stride=self.stride)
return dx
Relu层
class Relu:
def __init__(self):
self.mask = None
def forward(self ,X):
self.mask = X <= 0
out = X
out[self.mask] = 0
return out
def backward(self,dz):
dz[self.mask] = 0
dx = dz
return dx
SoftMax层
class SoftMax:
def __init__ (self):
self.y_hat = None
def forward(self,X):
self.y_hat = softmax(X)
return self.y_hat
def backward(self,labels):
m = labels.shape[0]
dx = (self.y_hat - labels)
return dx
def compute_cost(logits,label):
return cross_entropy_error(label,logits)
Affine FC层
class Affine:
def __init__(self,W,b):
self.W = W # shape is (n_x,n_unit)
self.b = b # shape is(1,n_unit)
self.X = None
self.origin_x_shape = None
self.dW = None
self.db = None
self.out_shape =None
def forward(self,X):
self.origin_x_shape = X.shape
self.X = X.reshape(X.shape[0],-1)#(m,n)
out = np.dot(self.X, self.W)+self.b
self.out_shape = out.shape
return out
def backward(self,dz,learning_rate):
"""
dz-- 前面的导数
"""
# print("Affine backward")
# print(self.X.shape)
# print(dz.shape)
# print(self.W.shape)
assert(dz.shape == self.out_shape)
m = self.X.shape[0]
self.dW = np.dot(self.X.T,dz)/m
self.db = np.sum(dz,axis=0,keepdims=True)/m
assert(self.dW.shape == self.W.shape)
assert(self.db.shape == self.b.shape)
dx = np.dot(dz,self.W.T)
assert(dx.shape == self.X.shape)
dx = dx.reshape(self.origin_x_shape) # 保持与之前的x一样的shape
#更新W和b
self.W = self.W-learning_rate*self.dW
self.b = self.b - learning_rate*self.db
return dx
模型
class SimpleConvNet:
def __init__(self):
self.X = None
self.Y= None
self.layers = []
def add_conv_layer(self,n_filter,n_c , f, stride=1, pad=0):
"""
添加一层卷积层
Arguments:
n_c -- 输入数据通道数,也即卷积层的通道数
n_filter -- 滤波器的个数
f --滤波器的长/宽
Return :
Conv -- 卷积层
"""
# 初始化W,b
W = np.random.randn(n_filter, n_c, f, f)*0.01
fb = np.zeros((1, n_filter))
# 卷积层
Conv = Convolution(W, fb, stride=stride, pad=pad)
return Conv
def add_maxpool_layer(self, pool_shape, stride=1, pad=0):
"""
添加一层池化层
Arguments:
pool_shape -- 滤波器的shape
f -- 滤波器大小
Return :
Pool -- 初始化的Pool类
"""
pool_h, pool_w = pool_shape
pool = Pooling(pool_h, pool_w, stride=stride, pad=pad)
return pool
def add_affine(self,n_x, n_units):
"""
添加一层全连接层
Arguments:
n_x -- 输入个数
n_units -- 神经元个数
Return :
fc_layer -- Affine层对象
"""
W= np.random.randn(n_x, n_units)*0.01
b = np.zeros((1, n_units))
fc_layer = Affine(W,b)
return fc_layer
def add_relu(self):
relu_layer = Relu()
return relu_layer
def add_softmax(self):
softmax_layer = SoftMax()
return softmax_layer
#计算卷积或池化后的H和W
def cacl_out_hw(self,HW,f,stride = 1,pad = 0):
return (HW+2*pad - f)/stride+1
def init_model(self,train_X,n_classes):
"""
初始化一个卷积层网络
"""
N,C,H,W = train_X.shape
#卷积层
n_filter = 4
f = 7
conv_layer = self.add_conv_layer(n_filter= n_filter,n_c=C,f=f,stride=1)
out_h = self.cacl_out_hw(H,f)
out_w = self.cacl_out_hw(W,f)
out_ch = n_filter
self.layers.append(conv_layer)
#Relu
relu_layer = self.add_relu()
self.layers.append(relu_layer)
#池化
f = 2
pool_layer = self.add_maxpool_layer(pool_shape=(f,f),stride=2)
out_h = self.cacl_out_hw(out_h,f,stride=2)
out_w = self.cacl_out_hw(out_w,f,stride=2)
#out_ch 不改变
self.layers.append(pool_layer)
#Affine层
n_x = int(out_h*out_w*out_ch)
n_units = 32
fc_layer = self.add_affine(n_x=n_x,n_units=n_units)
self.layers.append(fc_layer)
#Relu
relu_layer = self.add_relu()
self.layers.append(relu_layer)
#Affine
fc_layer = self.add_affine(n_x=n_units,n_units=n_classes)
self.layers.append(fc_layer)
#SoftMax
softmax_layer = self.add_softmax()
self.layers.append(softmax_layer)
def forward_progation(self,train_X, print_out = False):
"""
前向传播
Arguments:
train_X -- 训练数据
f -- 滤波器大小
Return :
Z-- 前向传播的结果
loss -- 损失值
"""
N,C,H,W = train_X.shape
index = 0
# 卷积层
conv_layer = self.layers[index]
X = conv_layer.forward(train_X)
index =index+1
if print_out:
print("卷积之后:"+str(X.shape))
# Relu
relu_layer = self.layers[index]
index =index+1
X = relu_layer.forward(X)
if print_out:
print("Relu:"+str(X.shape))
# 池化层
pool_layer = self.layers[index]
index =index+1
X = pool_layer.forward(X)
if print_out:
print("池化:"+str(X.shape))
#Affine层
fc_layer = self.layers[index]
index =index+1
X = fc_layer.forward(X)
if print_out:
print("Affline 层的X:"+str(X.shape))
#Relu
relu_layer = self.layers[index]
index =index+1
X = relu_layer.forward(X)
if print_out:
print("Relu 层的X:"+str(X.shape))
#Affine层
fc_layer = self.layers[index]
index =index+1
X = fc_layer.forward(X)
if print_out:
print("Affline 层的X:"+str(X.shape))
#SoftMax层
sofmax_layer = self.layers[index]
index =index+1
A = sofmax_layer.forward(X)
if print_out:
print("Softmax 层的X:"+str(A.shape))
return A
def back_progation(self,train_y,learning_rate):
"""
反向传播
Arguments:
"""
index = len(self.layers)-1
sofmax_layer = self.layers[index]
index -= 1
dz = sofmax_layer.backward(train_y)
fc_layer = self.layers[index]
dz = fc_layer.backward(dz,learning_rate=learning_rate)
index -= 1
relu_layer = self.layers[index]
dz = relu_layer.backward(dz)
index -= 1
fc_layer = self.layers[index]
dz = fc_layer.backward(dz,learning_rate=learning_rate)
index -= 1
pool_layer = self.layers[index]
dz = pool_layer.backward(dz)
index -= 1
relu_layer = self.layers[index]
dz = relu_layer.backward(dz)
index -= 1
conv_layer = self.layers[index]
conv_layer.backward(dz,learning_rate=learning_rate)
index -= 1
def get_minibatch(self,batch_data,minibatch_size,num):
m_examples = batch_data.shape[0]
minibatches = math.ceil( m_examples / minibatch_size)
if(num < minibatches):
return batch_data[num*minibatch_size:(num+1)*minibatch_size]
else:
return batch_data[num*minibatch_size:m_examples]
def optimize(self,train_X, train_y,minibatch_size,learning_rate=0.05,num_iters=500):
"""
优化方法
Arguments:
train_X -- 训练数据
train_y -- 训练数据的标签
learning_rate -- 学习率
num_iters -- 迭代次数
minibatch_size
"""
m = train_X.shape[0]
num_batches = math.ceil(m / minibatch_size)
costs = []
for iteration in range(num_iters):
iter_cost = 0
for batch_num in range(num_batches):
minibatch_X = self.get_minibatch(train_X,minibatch_size,batch_num)
minibatch_y = self.get_minibatch(train_y,minibatch_size,batch_num)
# 前向传播
A = self.forward_progation(minibatch_X,print_out=False)
#损失:
cost = compute_cost (A,minibatch_y)
#反向传播
self.back_progation(minibatch_y,learning_rate)
if(iteration%100 == 0):
iter_cost += cost/num_batches
if(iteration%100 == 0):
print("After %d iters ,cost is :%g" %(iteration,iter_cost))
costs.append(iter_cost)
#画出损失函数图
plt.plot(costs)
plt.xlabel("iterations/hundreds")
plt.ylabel("costs")
plt.show()
def predicate(self, train_X):
"""
预测
"""
logits = self.forward_progation(train_X)
one_hot = np.zeros_like(logits)
one_hot[range(train_X.shape[0]),np.argmax(logits,axis=1)] = 1
return one_hot
def fit(self,train_X, train_y):
"""
训练
"""
self.X = train_X
self.Y = train_y
n_y = train_y.shape[1]
m = train_X.shape[0]
#初始化模型
self.init_model(train_X,n_classes=n_y)
self.optimize(train_X, train_y,minibatch_size=10,learning_rate=0.05,num_iters=800)
logits = self.predicate(train_X)
accuracy = np.sum(np.argmax(logits,axis=1) == np.argmax(train_y,axis=1))/m
print("训练集的准确率为:%g" %(accuracy))
convNet = SimpleConvNet()
#拿20张先做实验
train_X = X_train[0:10]
train_y = y_train[0:10]
convNet.fit(train_X,train_y)
After 0 iters ,cost is :23.0254
After 100 iters ,cost is :14.5255
After 200 iters ,cost is :6.01782
After 300 iters ,cost is :5.71148
After 400 iters ,cost is :5.63212
After 500 iters ,cost is :5.45006
After 600 iters ,cost is :5.05849
After 700 iters ,cost is :4.29723
output_32_1.png
训练集的准确率为:0.9
预测
logits = convNet.predicate(X_train[0:10])
m = 10
accuracy = np.sum(np.argmax(logits,axis=1) == np.argmax(y_train[0:10],axis=1))/m
print("训练的准确率为:%g" %(accuracy))
训练的准确率为:0.9
index = 0
plt.imshow(X_train[index].reshape((28,28)),cmap = plt.cm.gray)
print("y is:"+str(np.argmax(y_train[index])))
print("your predicate result is :"+str(np.argmax(logits[index])))
y is:5
your predicate result is :5
output_35_1.png
logits = convNet.predicate(X_test)
m = X_test.shape[0]
accuracy = np.sum(np.argmax(logits,axis=1) == np.argmax(y_test,axis=1))/m
print("测试的准确率为:%g" %(accuracy))
测试的准确率为:0.1031
因为训练的数据只有10个,所以测试的准确率只有0.1。
本文的目的是实现CNN,了解CNN的过程。有一些辅助函数没有显示出来,用于将图像转成矩阵数据,方便卷积操作,然后再将其转换成图像用于后面的操作。如有兴趣,可以查看完整代码。完整代码链接:https://github.com/huanhuang/SimpleConvNet.git
实现过程有参考《深度学习入门》的 《卷积神经网络》那章,借用其思想,但实现有改动,对于图像转矩阵,矩阵转图像进行了改写,更易理解。
python基础代码库-CNN详解-基于python基础库实现的简单CNN相关推荐
- 利用python处理dna序列_详解基于python的全局与局部序列比对的实现(DNA)
程序能实现什么 a.完成gap值的自定义输入以及两条需比对序列的输入 b.完成得分矩阵的计算及输出 c.输出序列比对结果 d.使用matplotlib对得分矩阵路径的绘制 一.实现步骤 1.用户输入步 ...
- python selenium爬虫_详解基于python +Selenium的爬虫
详解基于python +Selenium的爬虫 一.背景 1. Selenium Selenium 是一个用于web应用程序自动化测试的工具,直接运行在浏览器当中,支持chrome.firefox等主 ...
- python怎么导入文件-Python文件如何引入?详解引入Python文件步骤
python基本语法--引入Python文件 1.新建python文件 :在同目录lib下创建mylib.py和loadlib.py两个文件 2.在mylib.py文件中创建一个Hello的类 并且给 ...
- python直线拟合_RANSAC算法详解(附Python拟合直线模型代码)
之前只是简单了解RANSAC模型,知道它是干什么的.然后今天有个课程设计的报告,上去讲了一下RANSAC,感觉这个东西也没那么复杂,所以今天就总结一些RASAC并用Python实现一下直线拟合. RA ...
- python编程入门与案例详解-quot;Python小屋”免费资源汇总(截至2018年11月28日)...
原标题:"Python小屋"免费资源汇总(截至2018年11月28日) 为方便广大Python爱好者查阅和学习,特整理汇总微信公众号"Python小屋"开通29 ...
- python编写数据库连接工具_详解使用Python写一个向数据库填充数据的小工具(推荐)...
一. 背景 公司又要做一个新项目,是一个合作型项目,我们公司出web展示服务,合作伙伴线下提供展示数据. 而且本次项目是数据统计展示为主要功能,并没有研发对应的数据接入接口,所有展示数据源均来自数据库 ...
- python zxing 识别条码_详解利用python识别图片中的条码(pyzbar)及条码图片矫正和增强...
前言 这周和大家分享如何用python识别图像里的条码.用到的库可以是zbar.希望西瓜6辛苦码的代码不要被盗了.(zxing的话,我一直没有装好,等装好之后再写一篇) 具体步骤 前期准备 用open ...
- python使用什么作为转义字符-详解用Python处理HTML转义字符的5种方式
写爬虫是一个发送请求,提取数据,清洗数据,存储数据的过程.在这个过程中,不同的数据源返回的数据格式各不相同,有 JSON 格式,有 XML 文档,不过大部分还是 HTML 文档,HTML 经常会混杂有 ...
- python main传参args,详解用Python处理Args的3种方法
1. sys 模块 Python 中的 sys 模块具有 argv 功能.当通过终端触发 main.py 的执行时,此功能将返回提供给 main.py 的所有命令行参数的列表.除了其他参数之外,返回列 ...
最新文章
- C++——auto_ptr与unique_ptr
- python count()计算字符出现的频数
- php用ajaxs上传图片_php+ajax实现图片文件上传功能实例
- 夺命雷公狗---linux NO:22 linux下的yum安装的高级配置
- DataTables中提示:DataTables warning: table id=example - Cannot reinitialise DataTable.
- 【转】详谈for循环里面的break和continue语句
- P4196 [CQOI2006]凸多边形 /【模板】半平面交
- 主机Window不能访问该虚拟机Linux Samba文件服务提供了一个文件夹
- xpe低配置系统解决“写缓存失败”问题
- 这就是数据分析之算法认知
- centos关闭邮件提醒
- c/c++ 指针函数 和 函数指针
- Tyvj-Begin P1029 Begin1 - Unit6 - 幼稚的把戏
- 电子设计竞赛作品设计步骤
- .net 6 简单使用redis
- 计算机关机后 为何会亮,Win10系统电脑关机后主机电源灯依然亮着怎么解决
- a7100换电池_如何评价三星galaxy A7100(2016版)?
- python项目运行的软硬件环境_开发时的软硬件环境和运行时的软硬件环境分别是什么...
- 22一战上岸首师大电子信息经验分享|低成本获得大收益|电子信息
- xp系统迁移到固态硬盘_通过网络轻松传输,将XP迁移到Windows 7
热门文章
- (传送门) IDEA 控制台输出JVM的GC日志
- Pandas初学者代码优化指南
- spark uniq 本质上就是单词计数
- 矩阵管理——本质是职能分工,例如所有部门都执行财务部门制定的财务制度而不会各自为政...
- numpy 按照指定字段排序
- 【Codeforces1327A】: Sum of Odd Intergers C/C++题解
- 按次计费接口的简单实现思路
- python:函数可以返回值--编写脚本计算24 + 34 / 100 - 1023
- 原生JS和jQuery操作DOM的区别小结
- XHTML5 与 HTML 4.01的差异