深度学习-卷积神经网络-tf-DNN-50
1. my_nn
#!/usr/bin/python3
# -*- coding:utf-8 -*-
"""
Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
"""
import os
import gzip
import numpy as np
from sklearn.datasets import fetch_mldata
from sklearn.utils.extmath import safe_sparse_dot
def load_data(data_folder):
files = [
'train-labels-idx1-ubyte.gz', 'train-images-idx3-ubyte.gz',
't10k-labels-idx1-ubyte.gz', 't10k-images-idx3-ubyte.gz'
]
paths = []
for fname in files:
paths.append(os.path.join(data_folder, fname))
with gzip.open(paths[0], 'rb') as lbpath:
y_train = np.frombuffer(lbpath.read(), np.uint8, offset=8)
with gzip.open(paths[1], 'rb') as imgpath:
x_train = np.frombuffer(imgpath.read(), np.uint8, offset=16).reshape(
len(y_train), -1)
with gzip.open(paths[2], 'rb') as lbpath:
y_test = np.frombuffer(lbpath.read(), np.uint8, offset=8)
with gzip.open(paths[3], 'rb') as imgpath:
x_test = np.frombuffer(
imgpath.read(), np.uint8, offset=16).reshape(len(y_test), 28, 28)
return (x_train, y_train), (x_test, y_test)
def tran_y(y_true):
y_one = np.zeros(10)
y_one[int(y_true)] = 1
return y_one
(X, y), (test_images, test_labels) = load_data('data/')
print(X.shape)
print(y.shape)
y = np.array([tran_y(y[i]) for i in range(len(y))])
hidden_layer_size = [300, 100]
max_iter = 20 # todo
alpha = 0.001 # 正则项系数 Loss = bass_loss + alpha*regular_loss
learning_rate = 0.001
def log_loss(y_true, y_prob):
"""
这是一个计算对数损失(log loss)的函数,输入参数为真实标签(y_true)和预测概率(y_prob)。具体实现步骤如下:
1. 对预测概率进行裁剪,保证其在[1e-10, 1-1e-10]之间,避免出现取对数时出现无穷大或NaN的情况。
2. 判断预测概率和真实标签的维度是否为1,若为1则将其转化为二维数组。
3. 计算对数损失,公式为-sum(y_true * log(y_prob)) / y_prob.shape[0],其中y_true和y_prob均为二维数组,*表示元素间的乘积,/表示元素间的除法。
:param y_true:
:param y_prob:
:return:
"""
# 对数损失计算
y_prob = np.clip(y_prob, 1e-10, 1 - 1e-10)
if y_prob.shape[1] == 1:
y_prob = np.append(1 - y_prob, y_prob, axis=1)
if y_true.shape[1] == 1:
y_true = np.append(1 - y_true, y_true, axis=1)
return -np.sum(y_true * np.log(y_prob)) / y_prob.shape[0] # * 表示对应的位置相乘
def softmax(x):
"""
这是一个实现softmax函数的代码,它可以将一个向量转换为概率分布。softmax函数常用于神经网络中的分类问题。该函数的输入是一个n维向量,输出也是一个n维向量,其中每个元素的值都在0到1之间,且所有元素的和为1。
具体实现中,首先对输入向量进行归一化,即每个元素减去该向量中的最大值。这一步的目的是防止指数函数的溢出。然后使用指数函数对归一化后的向量进行变换,最后再次进行归一化,得到概率分布。
:param x:
:return:
"""
tmp = x - x.max(axis=1)[:, np.newaxis]
np.exp(tmp, out=x)
x /= x.sum(axis=1)[:, np.newaxis]
return x
def relu(x):
"""
这是一个Python函数,用于实现ReLU(Rectified Linear Unit)激活函数。它的作用是将输入的值x进行非线性转换,将负值变为0,保留正值。具体实现是通过使用NumPy库的clip函数,将x中小于0的值变为0,大于0的值保持不变。最后返回转换后的结果。
:param x:
:return:
"""
np.clip(x, 0, np.finfo(x.dtype).max, out=x)
return x
def relu_derivation(z, delta):
"""
relu的导数
z为0的改为零 有值的则保持不变
:param z:
:param delta:
:return:
"""
delta[z == 0] = 0
def gen_batch(n, bs):
"""
n 样本总数
bs batch_size 批次大小
返回一个切片的索引
:param n:
:param bs:
:return:
"""
stat = 0
for _ in range(int(n // bs)):
end = stat + bs
yield slice(stat, end)
if stat < n:
yield slice(stat, n)
# 样本条数6000 输入的特征 28*28=784
n_samples, n_features = X.shape
# 输出节点数10
n_outputs = y.shape[1]
# 批次的大小200
batch_size = min(200, n_samples)
layer_units = ([n_features] + hidden_layer_size + [n_outputs])
print("====>nn 各层的节点数: 输入层 2隐藏层 输出层:", layer_units)
n_layers = len(layer_units)
"""
这段代码看起来像是神经网络中的权重和偏置初始化过程。具体来说,这个神经网络有n_layers层,每一层的神经元数量由layer_units列表中的值决定。这个for循环遍历每一层,计算该层的输入和输出神经元数量(fan_in和fan_out),然后使用一个公式来计算初始权重的范围(init_bound),最后使用均匀分布来随机初始化权重和偏置(coef_init和intercept_init),并将它们存储在coefs_和intercepts_列表中。这个过程可以帮助神经网络更好地学习数据的特征。
"""
coefs_ = []
intercepts_ = []
# 输入层 --> 隐藏层1 --> 隐藏层2 --> 输出层
for i in range(n_layers - 1):
fan_in = layer_units[i]
fan_out = layer_units[i + 1]
factor = 6.
init_bound = np.sqrt(factor / (fan_in + fan_out))
coefs_init = np.random.uniform(-init_bound, +init_bound, (fan_in, fan_out))
coefs_.append(coefs_init)
intercepts_init = np.random.uniform(-init_bound, +init_bound, fan_out)
intercepts_.append(intercepts_init)
# 初始化各层的输出 用于存放正向传播的输出结果
# 第一层是感知层
# 这段代码是神经网络中的正向传播过程中的一部分。在神经网络中,每一层都有一些神经元,每个神经元都有一些权重和偏置,用于计算该神经元的输出。正向传播是指从输入层开始,不断将每一层的输出作为下一层的输入,最终得到输出层的输出结果。
# 在这段代码中,首先将输入层的输出X存入一个列表activations中。然后对于每一层,都创建一个空数组,用于存放该层的输出结果。这里的n_fan_out表示该层中神经元的个数,因此创建的空数组的大小为(batch_size, n_fan_out),其中batch_size表示一次正向传播中输入的数据样本数量。
# 最后,将所有层的输出结果存放在一个列表activations中,用于后续的计算。
activations = [X]
activations.extend(
np.empty((batch_size, n_fan_out)) for n_fan_out in layer_units[1:])
# 反向传播 对w进行调整 调整量delta 与 w的形状是一样的
deltas = [np.empty_like(a_layer) for a_layer in activations]
# 初始化层之间的w矩阵 偏Loss/偏w
coef_grads = [np.empty((n_fan_in, n_fan_out)) for n_fan_in, n_fan_out in
zip(layer_units[1:], layer_units[:-1])]
# 初始化层之间的b 偏Loss/偏b
intercepts_grads = [np.empty(n_fan_out) for n_fan_out in layer_units[1:]]
loss = 0.
# min batch 梯度下降
for it in range(max_iter):
arr = np.arange(n_samples)
np.random.shuffle(arr)
X = X[arr]
y = y[arr]
accumulated_loss = 0.
for batch_slice in gen_batch(n_samples, batch_size):
batch_x = X[batch_slice]
batch_y = y[batch_slice]
# 输入层赋值
activations[0] = batch_x
# 正向传播
for i in range(n_layers - 1):
# w*X + b
activations[i + 1] = safe_sparse_dot(activations[i], coefs_[i])
activations[i + 1] += intercepts_[i]
if (i + 1) != (n_layers - 1): # 如果是隐藏层 需要经过relu激活函数
activations[i + 1] = relu(activations[i + 1])
# 最后一层
activations[i + 1] = softmax(activations[i + 1])
# loss计算
loss = log_loss(batch_y, activations[-1])
# 正则项损失
l2_loss = np.sum(
np.array([np.dot(s.ravel(), s.ravel()) for s in coefs_]))
loss += (0.5 * alpha) * l2_loss / len(batch_y)
accumulated_loss += loss * len(batch_y)
# 反向传播 先计算最后一层last layer
last = n_layers - 2
deltas[last] = activations[-1] - batch_y # y_hat - y
# base loss梯度的计算 X*(y_hat-y)
coef_grads[last] = safe_sparse_dot(activations[last].T, deltas[last])
# L2 loss 梯度的计算 1/2*w**2 求导--> w
coef_grads[last] += (alpha * coefs_[last])
# 梯度 求平均
coef_grads[last] /= n_samples
# 截距项b的梯度 y_hat-y
intercepts_grads[last] = np.mean(deltas[last], 0)
# 反向传播
for i in range(n_layers - 2, 0, -1):
# delta_prev = delta*W*激活函数的导数
deltas[i - 1] = safe_sparse_dot(deltas[i], coefs_[i].T)
relu_derivation(activations[i], deltas[i - 1])
# 1. base Loss的梯度
coef_grads[i - 1] = safe_sparse_dot(activations[i - 1].T,
deltas[i - 1])
# 2. L2 loss的梯度
coef_grads[i - 1] += (alpha * coefs_[i - 1])
# 3. 求平均
coef_grads[i - 1] /= n_samples
# 4. 截距项的梯度
intercepts_grads[i - 1] = np.mean(deltas[i - 1], 0)
# 一次小批次正向传播 反向传播 结束后 跟新 w b
grads = coef_grads + intercepts_grads
# 更新量= -学习率*梯度
updates = [-learning_rate * grad for grad in grads]
# 跟新
for param, update in zip(coefs_ + intercepts_, updates):
param += update
# 每个epoch结束后 打印一下loss
loss_ = accumulated_loss / X.shape[0]
print("Iter:%s, loss=%.8f" % (it, loss_))
2. mnist_cnn
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
# 读取数据
mnist = input_data.read_data_sets('MNIST_data_bak/', one_hot=True)
# 截断的正态分布 标准差设置为0.1
def weight_variable(shape):
initial = tf.truncated_normal(shape, stddev=0.1)
return tf.Variable(initial)
# 因为使用的激活函数为relu, 给偏置项增加小的正值0.1 避免节点死亡(dead neurons)
def bias_variable(shape):
initial = tf.constant(0.1, shape=shape)
return tf.Variable(initial)
# conv2d 二维的卷积函数 x数入 W是卷积核 [5, 5, ,1, 32]
# 卷积核的尺寸 5*5 1代表channel mnist是单通道的灰色图片
# 32 代表卷积核 的数量 也就是这个卷积层会提取多少的feature_map
# strides=[1, 1, 1, 1] 当步长为1的时候 输出与输出会保持同样的尺寸
# [n_sample, height, width, channels]
def conv2d(x, W):
return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding="SAME")
# tf.nn.max_pool是tf中的最大池化函数 2*2 降为1*1
# max_pool是保留原始像素中灰度值最大的那个 即保留最显著的特征
# strides [n_sample, height, width, channels]
def max_pool_2x2(x):
return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1],
padding="VALID")
# 卷积的计算需要将1D的输入 转化成2D的图片结构 1*784 --> 28*28
# [-1, 28, 28, 1] -1代表数量不固定, 最后的1 代表1个通道
x = tf.placeholder(tf.float32, [None, 784])
y_ = tf.placeholder(tf.float32, [None, 10])
x_image = tf.reshape(x, [-1, 28, 28, 1])
W_conv1 = weight_variable([5, 5, 1, 32]) # 5*5的核 channel=1 数量32
b_conv1 = bias_variable([32]) # 核的数量32
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
h_pool1 = max_pool_2x2(h_conv1)
# 第个卷积层 与上面的一样
W_conv2 = weight_variable([5, 5, 32, 64])
b_conv2 = bias_variable([64])
h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
h_pool2 = max_pool_2x2(h_conv2)
# 经过2次的卷积池化 输出为 m*7*7*64
# 将第二层的输出 一张图片变成7*7*64 需要reshape转化成1D的向量
# 然后连接一个全连接层 节点的数量为 1024 并经过relu激活
W_fc1 = weight_variable([7 * 7 * 64, 1024])
b_fc1 = bias_variable([1024])
h_pool2_flat = tf.reshape(h_pool2, [-1, 7 * 7 * 64])
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)
# 防止过拟合 训练的时候使用dropout
keep_prob = tf.placeholder(tf.float32)
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
# 再添加一个隐藏层 节点数 256
W_fc_plus = weight_variable([1024, 256])
b_fc_plus = bias_variable([256])
h_fc_plus = tf.nn.relu(tf.matmul(h_fc1_drop, W_fc_plus) + b_fc_plus)
# 再接上dropout
h_fc_plus_drop = tf.nn.dropout(h_fc_plus, keep_prob)
# 接softmax分类
W_fc2 = weight_variable([256, 10])
b_fc2 = bias_variable([10])
y_conv = tf.nn.softmax(tf.matmul(h_fc_plus_drop, W_fc2) + b_fc2)
# 损失函数
cross_entropy = tf.reduce_mean(
-tf.reduce_sum(y_ * tf.log(y_conv), reduction_indices=[1]))
# 训练步骤
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy) # 学习率0.0001
# 预测准确率的计算
correct_prediction = tf.equal(tf.arg_max(y_conv, 1), tf.arg_max(y_, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
# 训练
with tf.Session() as sess:
tf.global_variables_initializer().run()
# 训练迭代次数
for i in range(2000):
batch = mnist.train.next_batch(50)
# 训练的过程中计算下精度
if i % 100 == 0:
train_acc = accuracy.eval(feed_dict={x: batch[0], y_: batch[1], keep_prob: 1.0})
print("train accuracy: %s" % train_acc)
train_step.run(feed_dict={x: batch[0], y_: batch[1], keep_prob: 0.5})
# 训练结束 测试集 验证下精度
x_test, y_test = mnist.test.next_batch(5000)
acc = accuracy.eval(feed_dict={x: x_test, y_: y_test, keep_prob: 1.0})
print("Test dataset acc: %s" % acc)
分类:
深度学习
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)