【深度学习】(1) 前向传播,附python完整代码

本文详细介绍了如何在TensorFlow 2.0中使用mnist数据集进行深度学习模型的前向传播过程,包括数据获取、预处理、网络构建和实际操作中的梯度计算与权重更新。通过实例演示了神经网络的权重初始化、激活函数应用以及损失函数计算。
摘要由CSDN通过智能技术生成

各位同学大家好,今天和大家分享一下TensorFlow2.0深度学习中前向传播的推导过程,使用系统自带的mnist数据集。

1. 数据获取

首先,我们导入需要用到的库文件和数据集。导入的x和y数据是数组类型,需要转换成tensor类型tf.convert_to_tensor(),再查看一下我们读入的数据有没有问题。

import numpy as np
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import datasets # 数据集工具
import os  # 设置一下输出框打印的内容
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' # '2'输出栏只打印error信息,其他乱七八糟的信息不打印

#(1)获取mnist数据集
(x,y),_ = datasets.mnist.load_data() 
#(2)转换成tensor类型,x数据类型一般为float32,y存放的是图片属于哪种具体类型,属于整型
x = tf.convert_to_tensor(x,dtype=tf.float32)
y = tf.convert_to_tensor(y,dtype=tf.int32)
#(3)查看数据内容
print('shape:',x.shape,y.shape,'\ndtype:',x.dtype,y.dtype)  #查看shape和数据类型
print('x的最小值:',tf.reduce_min(x),'\nx的最大值:',tf.reduce_max(x))  #查看x的数据范围
print('y的最小值:',tf.reduce_min(y),'\ny的最大值:',tf.reduce_max(y))  #查看y的数据范围
# 打印的结果如下
shape: (60000, 28, 28) (60000,) 
dtype: <dtype: 'float32'> <dtype: 'int32'>
x的最小值: tf.Tensor(0.0, shape=(), dtype=float32) 
x的最大值: tf.Tensor(255.0, shape=(), dtype=float32)
y的最小值: tf.Tensor(0, shape=(), dtype=int32) 
y的最大值: tf.Tensor(9, shape=(), dtype=int32)

2. 数据预处理

首先对x数据进行归一化处理,原来x的每个像素值在[0,255]之间,现在转变成[0,1]之间。刚导入的y数据的shape是[6000],一维,存放分类数,为了和最后的预测结果比较,对它one-hot编码shape变为[6000,10]存放每张图属于每一个分类的概率y.numpy()[0]表示第0张图像属于第5个分类的概率是1,属于其他分类的概率是0。再设置一个学习率lr,用于每次迭代完成后更新神经网络权重参数,初始学习率以 0.01 ~ 0.001 为宜。

#(4)预处理
x = x/255.  # 归一化处理,将x数据的范围从[0,255]变成[0,1]
y = tf.one_hot(y,depth=10) # y是分类数值,对它进行one-hot编码,shape变为[b,10]
y.numpy()[0]  # 查看编码后的y的数据
# array([0., 0., 0., 0., 0., 1., 0., 0., 0., 0.], dtype=float32)

lr = 1e-3 # 学习率,设置过大,会导致loss震荡,学习难以收敛;设置过小,那么训练的过程将大大增加

加载数据集tf.data.Dataset.from_tensor_slices()生成迭代器的 iter()返回迭代器的下一个项目next() 

#(5)指定一个选取数据的batch,一次取128个数据
train_db = tf.data.Dataset.from_tensor_slices((x,y)).batch(128)
train_iter = iter(train_db) # 指定迭代器
sample = next(train_iter) # 存放的每一个batch
# sample[0]存放x数据,sample[1]存放y数据,每个sample有128组图片
print('batch:',sample[0].shape,sample[1].shape)
# 打印结果: batch: (128, 28, 28) (128, 10)

3. 构建网络

输入特征x的shape为[128,28,28],即输入层有28*28个神经元,自定义隐含层1有256个神经元,隐含层2有128个神经元,最终输出结果是固定的10个分类。

根据每一层神经元的个数来确定每个连接层的shape,使用随机的截断高斯分布来初始化各个权重参数,将定义的变量从tensor类型,转变为神经网络类型variable类型

#(6)构建网络
# 输入层由输入多少个特征点决定,输出层根据有多少个分类决定
# 输入层shape[b,784],输出层shape[b,10]
# 构建网络,自定义中间层的神经元个数
# [b,784] => [b,256] => [b,128] => [b,10]

# 第一个连接层的权重和偏置,都变成tf.Variable类型,这样tf.GradientTape才能记录梯度信息
w1 = tf.Variable(tf.random.truncated_normal([784,256], stddev=0.1)) # 截断正态分布,标准差调小一点防止梯度爆炸
b1 = tf.Variable(tf.zeros([256])) #维度为[dim_out]
# 第二个连接层的权重和偏置
w2 = tf.Variable(tf.random.truncated_normal([256,128], stddev=0.1)) # 截断正态分布,维度为[dim_in, dim_out]
b2 = tf.Variable(tf.zeros([128])) #维度为[dim_out]
# 第三个连接层的权重和偏置
w3 = tf.Variable(tf.random.truncated_normal([128,10], stddev=0.1)) # 截断正态分布,维度为[dim_in, dim_out]
b3 = tf.Variable(tf.zeros([10])) #维度为[dim_out]

4. 前向传播运算

每一次迭代从train_db中取出128个样本数据,由于取出的x数据的shape是[128,28,28],需要将它的形状转变成[128,28*28]才能传入输入层tf.reshape()h = x @ w + b,本层的特征向量和权重做内积,再加上偏置,将计算结果放入激活函数tf.nn.relu(),得到下一层的输入特征向量。最终得到的输出结果out中存放的是每张图片属于每个分类的概率。

#(7)前向传播运算
for i in range(10):  #对整个数据集迭代10次
    # 对数据集的所有batch迭代一次
    # x为输入的特征项,shape为[128,28,28],y为分类结果,shape为[128,10]
    for step,(x,y) in enumerate(train_db): # 返回下标和对应的值
        # 这里的x的shape为[b,28*28],从[b,w,h]变成[b,w*h]
        x = tf.reshape(x,[-1,28*28]) #对输入特征项的维度变换,-1会自动计算b
    
        with tf.GradientTape() as tape: # 自动求导计算梯度,只会跟踪tf.Variable类型数据
            # ==1== 从输入层到隐含层1的计算方法为:h1 = w1 @ x1 + b1   
            # [b,784] @ [784,256] + [b,256] = [b,256]
            h1 = x @ w1 + b1  # 相加时会自动广播,改变b的shape,自动进行tf.broadcast_to(b1,[x.shape[0],256])
            # 激活函数,relu函数
            h1 = tf.nn.relu(h1)
            # ==2== 从隐含层1到隐含层2,[b,256] @ [256,128] + [b,128] = [b,128]
            h2 = h1 @ w2 + b2
            h2 = tf.nn.relu(h2)
            # ==3== 从隐含层2到输出层,[b,128] @ [128,10] + [b,10] = [b,10]
            out = h2 @ w3 + b3 # shape为[b,10]
            
            #(8)计算误差,输出值out的shape为[b,10],onehot编码后真实值y的shape为[b,10]
            # 计算均方差 mse = mean(sum((y-out)^2)
            loss_square = tf.square(y-out)  # shape为[b,10]
            loss = tf.reduce_mean(loss_square) # 得到一个标量
            
        # 梯度计算
        grads = tape.gradient(loss,[w1,b1,w2,b2,w3,b3])
        
        # 注意:下面的方法,运算返回值是tf.tensor类型,在下一次运算会出现错误
        # w1 = w1 - lr * grads[0] # grads[0]值梯度计算返回的w1,是grad的第0个元素

        # 权重更新,lr为学习率,梯度每次下降多少
        # 因此需要原地更新函数,保证更新后的数据类型不变tf.Variable
        w1.assign_sub(lr * grads[0])
        b1.assign_sub(lr * grads[1])    
        w2.assign_sub(lr * grads[2])  
        b2.assign_sub(lr * grads[3]) 
        w3.assign_sub(lr * grads[4])    
        b3.assign_sub(lr * grads[5]) 
        
        if step % 100 == 0: #每100次显示一次数据
            print(f"第{step+1}次迭代,loss为{np.float(loss)}") #loss是tensor变量

计算输出结果和真实结果之间的均方差作为模型损失。使用tf.GradientTape()中的梯度计算方法tape.gradient(),用于更新下一次迭代的权重参数。公式为w1 = w1 - lr * grads[n],但由于该公式返回的是tensor类型的变量,而tf.GradientTape()梯度计算方法只能跟踪计算tf.variable类型的数据。因此需要使用assign_sub()函数原地更新权重参数,不造成变量类型改变。

# 最后一次循环循环,loss的输出结果为:
第1次迭代,loss为0.08258605003356934
第101次迭代,loss为0.09005936980247498
第201次迭代,loss为0.0828738585114479
第301次迭代,loss为0.0822446346282959
第401次迭代,loss为0.08802710473537445
  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
深度学习是一种机器学习方法,其基本思想是通过对数据进行分层抽象和学习,建立多层神经网络模型实现对数据的高效分类、识别和预测。而反向传播算法是深度学习中用于训练神经网络的一种有效方法。下面是反向传播算法的 Python 代码示例: ```python # 反向传播算法的 Python 代码示例 import numpy as np # 定义sigmoid函数 def sigmoid(x): return 1 / (1 + np.exp(-x)) # 定义神经网络前向传播函数 def forward(X, W1, b1, W2, b2): z1 = np.dot(X, W1) + b1 a1 = sigmoid(z1) z2 = np.dot(a1, W2) + b2 y_hat = sigmoid(z2) return y_hat, z1, a1, z2 # 定义损失函数 def loss(y, y_hat): L = -y * np.log(y_hat) - (1 - y) * np.log(1 - y_hat) return L # 定义反向传播函数 def backward(X, y, y_hat, z1, a1, z2, W2): delta2 = (y_hat - y) * y_hat * (1 - y_hat) dW2 = np.dot(a1.T, delta2) db2 = np.sum(delta2, axis=0) delta1 = np.dot(delta2, W2.T) * a1 * (1 - a1) dW1 = np.dot(X.T, delta1) db1 = np.sum(delta1, axis=0) return dW1, db1, dW2, db2 # 训练神经网络 def train(X, y, hidden_size, epochs, lr): input_size = X.shape output_size = y.shape # 随机初始化权重和偏置 W1 = np.random.randn(input_size, hidden_size) b1 = np.zeros((1, hidden_size)) W2 = np.random.randn(hidden_size, output_size) b2 = np.zeros((1, output_size)) # 迭代训练神经网络 for i in range(epochs): # 前向传播计算输出和损失 y_hat, z1, a1, z2 = forward(X, W1, b1, W2, b2) L = loss(y, y_hat) # 反向传播计算梯度 dW1, db1, dW2, db2 = backward(X, y, y_hat, z1, a1, z2, W2) # 更新权重和偏置 W1 -= lr * dW1 b1 -= lr * db1 W2 -= lr * dW2 b2 -= lr * db2 # 每迭代10次输出一次损失 if i % 10 == 0: print("Epoch %d Loss %.4f" % (i, np.mean(L))) return W1, b1, W2, b2 # 测试模型 X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]]) y = np.array([, , , ]) hidden_size = 4 epochs = 1000 lr = 0.5 W1, b1, W2, b2 = train(X, y, hidden_size, epochs, lr) y_hat_test = forward(X, W1, b1, W2, b2) print("Final Prediction") print(y_hat_test) ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

立Sir

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值