BP神经网络:从Numpy到Tensorflow2实现

 用最简单的神经网络结构实现一幅灰度图像的彩色化。

BP网络即前馈神经网络,模型在完成一次训练后需要反向对训练过程中的参数进行优化调整,是最基础的神经网络,也是复杂网络结构的基础。

不做过多的原理性介绍,仅仅介绍如何进行结构实现。文章结尾放上Numpy实现与Keras实现。

目录

目标:实现从灰度图像(图1)到目标图像(图2)的变化

输入层

输出层

隐藏层

超参

过程1:输入层​隐藏层

过程2:隐藏层​输出层

学习率

激活函数

损失函数

优化器

推导

BP训练过程

1.将所有  整理为矩阵形式

2.随机生成

3.前向过程计算

4.反向传播

5.重复3、4知道达到指定步骤

代码

Numpy版本:

Tensorflow2 Keras版本:


目标:实现从灰度图像(图1)到目标图像(图2)的变化

BP神经网络:从Numpy到Tensorflow2实现

图1 原始图像

BP神经网络:从Numpy到Tensorflow2实现

图2 目标彩色图像

所谓神经网络,结构上需要三层结构:输入层、隐藏层、输出层

首先来解决输出层的问题。

输入层

首先需要拿到原始图像每个像素点BP神经网络:从Numpy到Tensorflow2实现的4邻域,即该像素点上下左右4个点:BP神经网络:从Numpy到Tensorflow2实现BP神经网络:从Numpy到Tensorflow2实现BP神经网络:从Numpy到Tensorflow2实现BP神经网络:从Numpy到Tensorflow2实现 ,加上该点共5个点的灰度值作为输入x

BP神经网络:从Numpy到Tensorflow2实现
BP神经网络:从Numpy到Tensorflow2实现 BP神经网络:从Numpy到Tensorflow2实现 BP神经网络:从Numpy到Tensorflow2实现
BP神经网络:从Numpy到Tensorflow2实现

为了提高效果也可为8邻域,此时输入x为9个灰度值

BP神经网络:从Numpy到Tensorflow2实现 BP神经网络:从Numpy到Tensorflow2实现 BP神经网络:从Numpy到Tensorflow2实现
BP神经网络:从Numpy到Tensorflow2实现 BP神经网络:从Numpy到Tensorflow2实现 BP神经网络:从Numpy到Tensorflow2实现
BP神经网络:从Numpy到Tensorflow2实现 BP神经网络:从Numpy到Tensorflow2实现 BP神经网络:从Numpy到Tensorflow2实现

相信你也已经发现,取邻域的操作对于位于图像中部的点来说并无困难,而图像边缘点才是需要着重处理的地方,如果图像较大的话,取邻域操作也可以直接从非边缘点开始,到临界点结束,忽略边缘点信息,而本例中的图像较小,我们采取“补零填充”的方法。

0 0 0
0 BP神经网络:从Numpy到Tensorflow2实现 BP神经网络:从Numpy到Tensorflow2实现
0 BP神经网络:从Numpy到Tensorflow2实现 BP神经网络:从Numpy到Tensorflow2实现

以图1 中的(0,0)点为例,对于该点,x应为{0, 0, BP神经网络:从Numpy到Tensorflow2实现BP神经网络:从Numpy到Tensorflow2实现BP神经网络:从Numpy到Tensorflow2实现} 顺序无关,不过所有点的取值过程都需要按照一个固定的顺序。

遍历待处理图像中所有的像素点,将BP神经网络:从Numpy到Tensorflow2实现个像素点的4邻域获取完毕,存储在一个

shape=[BP神经网络:从Numpy到Tensorflow2实现,5]的矩阵中,后续过程中将每一行数据作为一次输入。

输出层

输入已经确定,在设计隐藏层之前首先确定输出层,本例的输出自然就是图2 中BP神经网络:从Numpy到Tensorflow2实现对应的RGB三通道值,即输出层结点数为3,分别代表着RGB三通道中的一个。

隐藏层

对本例最简单的神经网络来说,一层在输入与输出之间的全链接层即可完成任务,至于隐藏层的神经元数量,则需要根据后续的训练过程自行优化,神经网络是一个全随机的过程,参数的设置绝大多数情况下要根据经验。

结构设计完成,接下来需要对神经网路的参数进行定义

超参

过程1:输入层BP神经网络:从Numpy到Tensorflow2实现隐藏层

在本例中我们知道,每一次输入均有1*5个值,由输出层到隐藏层的过程可以定义为一个函数过程:BP神经网络:从Numpy到Tensorflow2实现,式中,v代表权重,BP神经网络:从Numpy到Tensorflow2实现则为偏置,这两个参数的初始化可以自行定义,可以在一定范围内选取随机数,也可以选取固定值,或者全部取0,在后续的反向传播过程中会根据「梯度」进行更新。

过程2:隐藏层BP神经网络:从Numpy到Tensorflow2实现输出层

类似于过程1,从隐藏层到输出层的过程也可以定义为一个函数过程:BP神经网络:从Numpy到Tensorflow2实现,式中,w代表权重,BP神经网络:从Numpy到Tensorflow2实现也为偏置,初始化过程类似于过程1。

学习率

关于学习率的定义这里不做赘述,感兴趣的可以查看其他博主介绍的比较详细的文章,或者西瓜书上面的介绍。在这里我们只需要知道这是一个神经网络中非常重要的参数,可以取固定值或根据训练结果更新,更新的方式有很多种,本例中选取固定学习率。

激活函数

某一网络层向一下网络层传输数据之前,该网络层产生的结果通常需要先经过一个函数转换为一个值,这个函数称为激活函数,根据网络结构、目标的不同有多种选择。

损失函数

神经网络产生一次输出之后,这个输出需要与目标结果进行对比,即BP神经网络:从Numpy到Tensorflow2实现,通过损失函数计算出一个这两者之间的差异度量,作为反向传播中更新参数的依据,通常使用sigmoid系列的函数作为损失函数,根据数据类型的差异也有不同的选择。

优化器

优化器:神经网络中用于梯度下降的工具,有多种选择。学习率也是在优化器中使用的。


推导

下面对神经网络过程做一个纯公式的推导,损失函数使用sigmoid,损失函数为MSE(均方误差)

BP神经网络:从Numpy到Tensorflow2实现

BP神经网络:从Numpy到Tensorflow2实现表示输出层第BP神经网络:从Numpy到Tensorflow2实现个神经元编号

BP神经网络:从Numpy到Tensorflow2实现表示隐藏层第BP神经网络:从Numpy到Tensorflow2实现个神经元编号

BP神经网络:从Numpy到Tensorflow2实现表示输出层第BP神经网络:从Numpy到Tensorflow2实现 个神经元编号

BP神经网络:从Numpy到Tensorflow2实现分别表示输入层、隐藏层、输出层神经元个数。

 BP神经网络:从Numpy到Tensorflow2实现表示第 BP神经网络:从Numpy到Tensorflow2实现个输入层神经元与第BP神经网络:从Numpy到Tensorflow2实现 个隐层神经元的连接权值  

BP神经网络:从Numpy到Tensorflow2实现表示第 BP神经网络:从Numpy到Tensorflow2实现个隐层神经元与第 BP神经网络:从Numpy到Tensorflow2实现个输出层神经元的连接权值  

BP神经网络:从Numpy到Tensorflow2实现表示第BP神经网络:从Numpy到Tensorflow2实现 个隐层神经元输入偏置 

BP神经网络:从Numpy到Tensorflow2实现表示第 BP神经网络:从Numpy到Tensorflow2实现个输出层神经元输入偏置

 BP神经网络:从Numpy到Tensorflow2实现 表示第BP神经网络:从Numpy到Tensorflow2实现 个输入样本

BP神经网络:从Numpy到Tensorflow2实现 表示第 BP神经网络:从Numpy到Tensorflow2实现个样本经过神经网络的预测输出

BP神经网络:从Numpy到Tensorflow2实现表示第 BP神经网络:从Numpy到Tensorflow2实现个样本的真实输出

隐层第 BP神经网络:从Numpy到Tensorflow2实现个神经元的输入BP神经网络:从Numpy到Tensorflow2实现 可表示为

BP神经网络:从Numpy到Tensorflow2实现 (1)

隐层第 BP神经网络:从Numpy到Tensorflow2实现个神经元的输出BP神经网络:从Numpy到Tensorflow2实现 可表示为 

BP神经网络:从Numpy到Tensorflow2实现   (2)

输出层第BP神经网络:从Numpy到Tensorflow2实现 个神经元输入:

BP神经网络:从Numpy到Tensorflow2实现​​​​​​​ (3)

输出层第BP神经网络:从Numpy到Tensorflow2实现个神经元输出:

BP神经网络:从Numpy到Tensorflow2实现 (4)

给定输出样本BP神经网络:从Numpy到Tensorflow2实现

神经网络预测输出BP神经网络:从Numpy到Tensorflow2实现

可通过(1) BP神经网络:从Numpy到Tensorflow2实现(2)BP神经网络:从Numpy到Tensorflow2实现 (3)BP神经网络:从Numpy到Tensorflow2实现 (4) 计算

上述过程以矩阵形式可表示为:

BP神经网络:从Numpy到Tensorflow2实现 

 BP神经网络:从Numpy到Tensorflow2实现

BP神经网络:从Numpy到Tensorflow2实现

BP神经网络:从Numpy到Tensorflow2实现

BP神经网络:从Numpy到Tensorflow2实现

BP神经网络:从Numpy到Tensorflow2实现

BP神经网络:从Numpy到Tensorflow2实现

BP神经网络:从Numpy到Tensorflow2实现

给定N个输入输出样本BP神经网络:从Numpy到Tensorflow2实现

BP神经网络:从Numpy到Tensorflow2实现

经神经网络预测输出为:

BP神经网络:从Numpy到Tensorflow2实现

前馈项:

BP神经网络:从Numpy到Tensorflow2实现

神经网络模型矩阵表示

以回归任务为例

神经网络参数评估采用均方差MSE

BP神经网络:从Numpy到Tensorflow2实现

采用梯度下降方法求解网络最优参数

BP神经网络:从Numpy到Tensorflow2实现

BP神经网络:从Numpy到Tensorflow2实现

BP神经网络:从Numpy到Tensorflow2实现

BP神经网络:从Numpy到Tensorflow2实现

梯度求解采用矩阵形式可表示为

BP神经网络:从Numpy到Tensorflow2实现

符号表示矩阵的点乘

BP神经网络:从Numpy到Tensorflow2实现

BP神经网络:从Numpy到Tensorflow2实现​​​​​​​

BP神经网络:从Numpy到Tensorflow2实现

(以上推导过程应该有一些顺序或者加减上的小问题,在numpy版本的代码中已经更正(大概))

BP训练过程

给定训练数据BP神经网络:从Numpy到Tensorflow2实现

步骤:

1.将所有 BP神经网络:从Numpy到Tensorflow2实现 整理为矩阵形式

 BP神经网络:从Numpy到Tensorflow2实现

2.随机生成BP神经网络:从Numpy到Tensorflow2实现

3.前向过程计算

BP神经网络:从Numpy到Tensorflow2实现

4.反向传播

计算BP神经网络:从Numpy到Tensorflow2实现

BP神经网络:从Numpy到Tensorflow2实现

BP神经网络:从Numpy到Tensorflow2实现是学习率)

5.重复3、4知道达到指定步骤


代码

下面上代码

Numpy版本:

import cv2
import numpy as np
import time

ori_path='ori.png'
res_path='res.png'
output_path='output_numpy_version.jpg'

#循环次数(即遍历整张图的次数)
ecp_num=10

def sigmoid(x):
    return 1/(1+np.exp(0-x))

#本例使用5*5大小的块作为输入
def get5pixel(arr):
    arr=np.pad(arr,2,'constant')
    ers=np.zeros(shape=(151*144,25))
    t=0
    for i in range(2,153):
        for j in range(2,146):
            tmp=arr[i-2:i+3,j-2:j+3]
            ers[t]=np.reshape(tmp,(1,25))
            t=t+1
    return ers

#规定输出
def getColor(arr):
    res=np.zeros(shape=(151*144,3))
    t=0
    for i in range(151):
        for j in range(144):
            res[t]=arr[i,j]
            t=t+1
    return res

img_ori=cv2.imread(ori_path)
img_res=cv2.imread(res_path)
#转为灰度图像
img_ori=cv2.cvtColor(img_ori,cv2.COLOR_BGR2GRAY)
#归一化
img_ori=img_ori/255
img_res=img_res/255

x_pixel=get5pixel(img_ori)
y_color=getColor(img_res)

v=np.random.random_sample(size=(25,64))
b1=np.zeros(shape=(64,1))
w=np.random.random_sample(size=(64,3))
b2=np.zeros(shape=(1,3))

#创建用于存放结果的空矩阵
data_pre=np.zeros(shape=(151*144,3))

learn_rate=1

def update(new,old):
    return old-learn_rate*new

def backword(t,h_out):
    global v,b1,w,b2,y_color,data_pre
    ow=w
    ob2=b2
    ob1=b1
    ov=v
    b2=(data_pre[t]-y_color[t,:])*data_pre[t]*(np.full((1,3),1)-data_pre[t])
    w=np.dot(h_out,b2)
    b1=(np.dot(b2,ow.T)*h_out.T*(np.full(64,1)-h_out).T).T
    v=np.reshape(x_pixel[t,:],(25,1))*b1.T

    b2=update(b2,ob2)
    w=update(w,ow)
    b1=update(b1,ob1)
    v=update(v,ov)

def forword():
    for t in range(151*144):
        hidden_in=np.reshape((np.dot(x_pixel[t,:],v)).T,(64,1))
        hidden_out=hidden_in+b1
        out_in=np.zeros(shape=(64,1))
        for i in range(64):
            out_in[i,:]=sigmoid(hidden_out[i,:])
        out_out=np.dot(out_in.T,w)+b2
        for i in range(3):
            out_out[0,i]=sigmoid(out_out[0,i])
        data_pre[t]=out_out
        backword(t,out_in)
    
for i in range(ecp_num):
    a=time.time()
    forword()
    b=time.time()
    print('rang',i,'cost_sc',b-a)

result=np.reshape(data_pre,(155,144,3))
cv2.imwrite(output_path,result*255)
print('done')

Tensorflow2 Keras版本:

keras是tensorflow 的高级封装,大大简化了神经网络的设计过程。

import cv2
import numpy as np
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers

#与numpy版本数据处理相同
def get_piexl_5(arr):
    arr = np.pad(arr, 2, 'constant')
    ers = np.zeros(shape=(151*144, 25))
    t = 0
    for i in range(2, 153):
        for j in range(2, 146):
            tmp = arr[i - 2:i + 3, j - 2:j + 3]
            tmp = np.reshape(tmp, (1, 25))
            ers[t] = tmp
            t = t + 1
    return ers


def get_pixel_color(arr):
    res = np.zeros(shape=(151 * 144, 3))
    t = 0
    for i in range(151):
        for j in range(144):
            res[t] = arr[i, j]
            t = t + 1
    return res


ori_img = cv2.imread('.\\ori.png')
res_img = cv2.imread('.\\res.png')

ori_img=cv2.cvtColor(ori_img,cv2.COLOR_BGR2GRAY)
ori_img = ori_img / 255
ori_img = get_piexl_5(ori_img)
#转张量
t = tf.convert_to_tensor(ori_img)

res_img = res_img / 255
res_data = get_pixel_color(res_img)

#以下为使用keras函数式API构建网络结构
#输入层,(25,)的张量
img_imputs = keras.Input(shape=(25,),name='Input')
# initializer = keras.initializers.RandomUniform(minval=0., maxval=1.)
#偏置初始化
initializer_2 = keras.initializers.TruncatedNormal(mean=0.5,stddev=0.5)
initializer_1 = keras.initializers.Zeros()
#64个神经元的全链接层,激活函数为sigmoid,使用偏置,使用权重(kernel)
dense = layers.Dense(64, activation='sigmoid', use_bias=True, kernel_initializer=initializer_2,
                     bias_initializer=initializer_1, name='Dense')(img_imputs)
#输出层,3个神经元
outputs = layers.Dense(3, activation='sigmoid', use_bias=True, kernel_initializer=initializer_2,
                       bias_initializer=initializer_1, name='OutPut')(dense)
#build模型
model = keras.Model(inputs=img_imputs, outputs=outputs, name="m_model")
#打印网络结构
print(model.summary())
#此行会生成一张网络结构图,需要的依赖较多,可以删去
keras.utils.plot_model(model, '.\\model_info.png', show_shapes=True)

#确定损失函数、优化器、评价标准等
model.compile(
    loss=keras.losses.MeanSquaredError(),
    # loss=keras.losses.BinaryCrossentropy(),
    optimizer=keras.optimizers.SGD(learning_rate=1),
    metrics=["accuracy"]
)

x_train = t
y_train = tf.convert_to_tensor(res_data)
x_test = t
y_test = y_train

#训练
history = model.fit(x_train, y_train,batch_size=64 ,epochs=50)

#查看训练中间过程
test_scores = model.evaluate(x_test, y_test, verbose=0)

print("Test loss:", test_scores[0])
print("Test accuracy:", test_scores[1])

#保存整个模型,下次可以直接读取文件进行调用
# model.save('.\\model')
#预测
res=model.predict(x_test)
res = np.reshape(res, (151, 144, 3))
res = res * 255
cv2.imwrite(".\\ult_32.jpg", res)

BP神经网络:从Numpy到Tensorflow2实现

不能说是毫无关系,只能说是一模一样。

(numpy版本完成时间过久,已经忘记了是否能够跑通,如果报错可以尝试修改反向传播过程中的维度)

有问题欢迎留言

上一篇:tensorflow2预测新文本


下一篇:autoCAD的快速选择功能介绍(图)