文章目录
- 1.多分类任务
- 1.MNIST数据集
- 2.多分类损失函数
- 3.手写识别:训练
- 4.手写识别:使用
- 5.自定义更新写法
- 2.使用Tensorflow构建神经网络
- 1.导入mnist数据集
- 2.构建神经网络模型
- 3.神经网络中所用函数
- 4.神经网络训练更新
1.多分类任务
1.MNIST数据集
训练数据:6万张
测试数据:1万张
2.多分类损失函数
- 虚拟变量
取值为0或1的变量,当对象属于虚拟变量代表的类别时,取值为1。
常用于解决多分类问题,先将多分类变量转变为虚拟变量 - 独热编码(one-hot)
N个状态:N个寄存器进行编码,且任意时候只有一位有效
import pandas as pd
# 独热编码
df = pd.DataFrame([['one'],['two'],['three']],columns = ['y'])
# pd.DataFrame()创建带标签的二维数组,(data数据,index=行标签,columns=列标签),标签默认0-n
print(df)
df_oh = pd.get_dummies(df['y'])
# pd.get_dummies()对虚拟变量进行编码
print(df_oh)
print(df_oh[['one','two','three']]) #形式转换
- 损失函数
1.0-1损失函数(0-1 Loss)
2.二元交叉熵(binary crossentropy)
yi 样本i的标签,1或0
pi 样本i标签为yi 的几率
3.稀疏分类交叉熵(sparse categorical crossentropy)
优点:偏导数易于获取,模型差时学习速率快
缺点:矩阵参数随类别数增大而增大,开放集学习问题
3.手写识别:训练
- 导入mnist数据集
from tensorflow import keras
import matplotlib.pyplot as plt
mnist = keras.datasets.mnist #导入MNIST数据集
(train_images,train_labels),(test_images,test_labels) = mnist.load_data() #将数据集分为训练集和测试集
print(type(train_images),train_images.shape) #train_images的类型,大小
print(train_labels) #查看train_labels
plt.imshow(train_images[0]) #画第一幅图
plt.colorbar()
plt.show()
print(train_labels[0])
- 归一化
train_images,test_images = train_images/255.0,test_images/255.0 #将图 片转为灰度图,数值范围0-1,归一化
plt.imshow(train_images[0],cmap = plt.cm.binary) #画第一幅图, plt.cm.binary 黑白色彩
plt.colorbar()
plt.show()
plt.figure(figsize = (10,10)) #显示多张图片
for i in range(25):
plt.subplot(5,5,i+1)
plt.xticks([]) #去除x y的坐标刻度
plt.yticks([])
plt.imshow(train_images[i], cmap = plt.cm.binary) #plt.cm.binary 黑白色彩
plt.xlabel(train_labels[i]) #将x轴标签替换为手写数字
plt.show()
- 模型构建与编译
import numpy as np
model = keras.Sequential( #构建神经网络模型
[
keras.layers.Flatten(input_shape = (28,28)), #第一层,Flatten()将二维数组降成一维
keras.layers.Dense(128,activation = 'relu'), #第二层
keras.layers.Dense(10,activation = 'softmax') #第三层,输出层
]
)
print(model.summary()) #输出模型概述
model.compile(optimizer = 'adam',
loss = 'sparse_categorical_crossentropy', #设置模型损失函数为稀疏分类交叉熵
metrics = ['accuracy'])
model.fit(train_images,train_labels,epochs = 5,verbose = 0) #开始训练模型,5次,不输出
test_loss,test_acc = model.evaluate(test_images,test_labels) #模型评价
print('Test accuracy:',test_acc) #输出模型准确率
predictions = model.predict(test_images) #模型预测
print(np.argmax(predictions[0])) #argmax()返回其中元素最大值所对应的索引
4.手写识别:使用
- 模型评估
def plot_image(i,predictions_array,true_label,img): #自定义绘数字图函数
predictions_array,true_label,img = predictions_array,true_label[i],img[i]
plt.xticks([]) #去除x y刻度
plt.yticks([])
plt.imshow(img,cmap = plt.cm.binary)
predicted_label = np.argmax(predictions_array) #预测数字
if predicted_label == true_label: #如果预测等于实际,颜色蓝色
color = 'b'
else:
color = 'r' #如果与实际不符,颜色红色
plt.xlabel('%d %.2f%s(%d)'%(predicted_label,np.max(predictions_array)*100,'%',true_label))
# x轴标签 预测值 预测值概率 真实值
def plot_value_array(i,predictions_array,true_label): #自定义绘柱状图
predictions_array,true_label = predictions_array,true_label[i]
plt.xticks(range(10)) # x轴标签0-9
plt.yticks([]) # y轴无标签
thisplot = plt.bar(range(10),predictions_array,color = '#777777') #绘制柱状图并暂时储存thisplot,x柱子坐标,height柱子高度,color柱子颜色,'#777777'灰色
plt.ylim(0,1) #设置y轴的范围0-1
predicted_label = np.argmax(predictions_array) #预测数字
thisplot[predicted_label].set_color('r') #将预测数字设置为蓝色
thisplot[true_label].set_color('b') #将真实数字设置为红色
#开始绘图
i = 0
plt.figure(figsize = (6,3)) #设置总绘图大小
plt.subplot(1,2,1) #绘制第一个子图
plot_image(i,predictions[i],test_labels,test_images)
plt.subplot(1,2,2) #绘制第二个子图
plot_value_array(i,predictions[i],test_labels)
plt.show()
#绘制多幅连续子图
num_rows = 5 #行数
num_cols = 3 #列数
num_images = num_rows*num_cols #总图数目
plt.figure(figsize = (2*2*num_cols,2*num_rows))
for j in range(num_images):
plt.subplot(num_rows,2*num_cols,2*j+1) #绘制第一个子图
plot_image(i+j,predictions[i+j],test_labels,test_images)
plt.subplot(num_rows,2*num_cols,2*j+2)
plot_value_array(i+j,predictions[i+j],test_labels)
plt.tight_layout() #自动调整子图参数,使其填充整个图像区域
plt.show()
- 对本地文件进行识别
from PIL import Image
#对本地图片进行手写识别
img = Image.open('my_num.bmp') #导入本地图片
img = np.array(img) #将图片转化为数组
img = img/255.0 #将数组转为0-1之间
my_num = 1-img #白为1转为黑为1
my_num = my_num.reshape(1,28,28) #改变数组形状
plt.imshow(my_num[0],cmap = plt.cm.binary) #绘图
plt.colorbar()
plt.show()
res = model.predict(my_num) #输出预测数字
print(np.argmax(res))
5.自定义更新写法
- 离散化权重
import numpy as np
import matplotlib.pyplot as plt
#权重操作
G_min = -1 #最小值
G_max = 1 #最大值
A_p = 0.8
A_d = 0.8
def LTP(P):
return (G_max - G_min) * (1 - np.exp(P / A_p)) / (1 - np.exp(1 / A_p)) + G_min # 向上更新
def LTD(P):
return (G_max - G_min) * (1 - np.exp((1 - P) / A_d)) / (1 - np.exp(1 / A_d)) + G_min # 向下更新
def L(P):
return (G_max - G_min) * P + G_min #线性
x = np.linspace(0,1,20) #创建数组
y = []
for p in x:
y.append(LTP(p)) #在y数组末尾添加
plt.scatter(x,y) #绘制散点图
plt.show()
y = []
for p in x:
y.append(LTD(p)) #在y数组末尾添加
plt.scatter(x,y) #绘制散点图
plt.show()
y = [] #线性
for p in x:
y.append(L(p)) #在y数组末尾添加
plt.scatter(x,y) #绘制散点图
plt.show()
- 自定义权重更新
import tensorflow as tf
from tensorflow import keras
mnist = keras.datasets.mnist #导入mnist数据集
(train_images,train_labels),(test_images,test_labels) = mnist.load_data() #数据集分为训练集和测试集
train_images,test_images = train_images/255.0,test_images/255.0 #将图片转为灰度图,数值范围0-1
model = keras.Sequential( #构建神经网络模型
[
keras.layers.Flatten(input_shape = (28,28)), #第一层,Flatten()将二维数组降成一维
keras.layers.Dense(128,activation = 'relu',use_bias = False), #第二层,use_bias = False不使用偏移量b
keras.layers.Dense(10,activation = 'softmax',use_bias = False) #第三层,输出层
]
)
model.compile(optimizer = 'sgd', #使用梯度下降来优化
loss = 'sparse_categorical_crossentropy', #设置模型损失函数为稀疏分类交叉熵
metrics = ['accuracy'])
P10 = 100*(np.random.rand(28*28,128))+0.5 #生成随机数组,数值范围0-100,大小784*128,*100离散化,+0.5便于四舍五入
P1 = P10.astype(int) #将浮点数转换为整数,astype数据类型转换
P20 = 100*(np.random.rand(128,10))+0.5 #随机数组,大小125*10
P2 = P20.astype(int) #类型转换
def ini_net(model,P1,P2): #神经网络模型初始化
weight_1 = 2*(P1/100-0.5) #权重,范围-1到1
weight_2 = 2*(P2/100-0.5)
weights = [weight_1,weight_2] #总权重数组
model.set_weights(weights) #模型设置权重
def update_net(model,func_p,func_d): #自定义模型更新函数
weights_bak = model.get_weights() #获取原来模型的权重
model.fit(train_images,train_labels,epochs = 1,verbose = 0) #模型训练一次,不输出
weights = model.get_weights() #获取训练后模型的权重
for i in range(len(weights[0])):
for j in range(len(weights[0][0])):
if weights[0][i][j] > weights_bak[0][i][j]: #如果原来权重大于训练后权重
if(P1[i][j] < 100): #如果权重小于1大于-1时才更新权重
P1[i][j] +=1 #每次更新加0.01
weights[0][i][j] = func_p(P1[i][j]/100)
elif weights[0][i][j] < weights_bak[0][i][j]: #如果原来权重小于训练后权重
if(P1[i][j] > 0): #如果权重小于1大于-1时才更新权重
P1[i][j] -=1 #每次更新减0.01
weights[0][i][j] = func_d(P1[i][j]/100)
for i in range(len(weights[1])):
for j in range(len(weights[1][0])):
if weights[1][i][j] > weights_bak[1][i][j]: #如果原来权重大于训练后权重
if(P1[i][j] < 100): #如果权重小于1大于-1时才更新权重
P1[i][j] +=1 #每次更新加0.01
weights[1][i][j] = func_p(P1[i][j]/100)
elif weights[1][i][j] < weights_bak[1][i][j]: #如果原来权重小于训练后权重
if(P1[i][j] > 0): #如果权重小于1大于-1时才更新权重
P1[i][j] -=1 #每次更新减0.01
weights[1][i][j] = func_d(P1[i][j]/100)
model.set_weights(weights) #设置更新后权重
EPOCHS = 20 #更新次数
ini_net(model,P1,P2) #初始化
acc1 = [] #储存线性准确度
for epochs in range(EPOCHS):
update_net(model,L,L) #线性更新
train_loss,train_acc = model.evaluate(train_images,train_labels) #评价模型
acc1.append(train_acc)
test_loss,test_acc = model.evaluate(test_images,test_labels) #检验模型
#重新初始化模型
P1 = P10.astype(int) #将浮点数转换为整数,astype数据类型转换
P2 = P20.astype(int) #类型转换
ini_net(model,P1,P2) #初始化
acc2 = [] #储存线性准确度
for epochs in range(EPOCHS):
update_net(model,LTP,LTP) #非线性更新(0.8 0.8)
train_loss,train_acc = model.evaluate(train_images,train_labels) #评价模型
acc2.append(train_acc)
test_loss,test_acc = model.evaluate(test_images,test_labels) #检验模型
plt.plot(np.arange(1,21),acc1,'o-') #np.arange()返回起点到终点固定步长的数组,步长默认1, plt.plot()绘制点线图
plt.plot(np.arange(1,21),acc2,'o-')
plt.show()
2.使用Tensorflow构建神经网络
1.导入mnist数据集
import numpy as np
import tensorflow as tf
from tensorflow import keras
gpus = tf.config.list_physical_devices('GPU') #查看当前主机上GPU列表
tf.config.experimental.set_memory_growth(gpus[0],True) #动态申请显存
mnist = keras.datasets.mnist #导入mnist数据集
(x_train,y_train),(x_test,y_test) = mnist.load_data() #数据集分为训练集和测试集
x_train,x_test = np.array(x_train,np.float32),np.array(x_test,np.float32) #64位浮点数变为32位浮点数
x_train,x_test = x_train/255.0,x_test/255.0 #将图片转为灰度图,数值范围0-1
x_train,x_test = x_train.reshape(-1,28*28),x_test.reshape(-1,28*28) #三维变二维,-1模糊控制,固定28*28列
print(x_train.shape,x_test.shape) #输出其形状
2.构建神经网络模型
n_hidden_1 = 128 #每层神经元数目
n_hidden_2 = 256
random_normal = tf.initializers.RandomNormal() #生成服从正态分布的随机张量
weights = { #权重
'h1':tf.Variable(random_normal([28*28,n_hidden_1])), #第一层
'h2':tf.Variable(random_normal([n_hidden_1,n_hidden_2])), #第二层
'out':tf.Variable(random_normal([n_hidden_2,10])) #输出层
}
biases = { #偏移量
'b1':tf.Variable(tf.zeros([n_hidden_1])), #初始为零,第一层
'b2':tf.Variable(tf.zeros([n_hidden_2])), #第二层
'out':tf.Variable(tf.zeros([10])) #输出层
}
3.神经网络中所用函数
def neural_net(x): #自定义神经网络函数
#第一层
layer_1 = tf.add(tf.matmul(x,weights['h1']),biases['b1']) #返回x*h1+b1
layer_1 = tf.nn.sigmoid(layer_1) #激活函数sigmoid
#第二层
layer_2 = tf.add(tf.matmul(layer_1,weights['h2']),biases['b2']) #返回layer_1*h2+b2
layer_2 = tf.nn.sigmoid(layer_2) # 激活函数sigmoid
#输出层
out_layer = tf.add(tf.matmul(layer_2,weights['out']),biases['out'])
return tf.nn.softmax(out_layer) #激活函数softmax
def cross_entropy(y_pred,y_true): #自定义稀释函数交叉熵
y_true = tf.one_hot(y_true,10) #tf.one_hot()将向量y_true转换为独热编码的形式,10个类别
y_pred = tf.clip_by_value(y_pred,1e-9,1.0) #tf.clip_by_value()将张量数值控制在特定范围,1e-9到1
return tf.reduce_mean(-tf.reduce_sum(y_true*tf.math.log(y_pred),1)) #tf.reduce_mean()求平均值,tf.reduce_sum()求和
def accuracy(y_pred,y_true): #自定义准确率
correct_prediction = tf.equal(tf.argmax(y_pred,1),tf.cast(y_true,tf.int64)) #tf.equal()张量值相等返回true否则返回false
return tf.reduce_mean(tf.cast(correct_prediction,tf.float32)) #tf.cast()转换为指定类型
4.神经网络训练更新
EPOCHS = 100 #训练次数
for epoch in range(EPOCHS): #梯度下降方法
with tf.GradientTape() as tape: #自动记录微分操作
pred_val = neural_net(x_train)
loss = cross_entropy(pred_val,y_train)
trainable_var = list(weights.values())+list(biases.values())
grads = tape.gradient(loss,trainable_var) #计算梯度
optimizer = tf.optimizers.Adam() #用自适应矩估计来优化
optimizer.apply_gradients(zip(grads,trainable_var)) #zip()将对应元素打包成一个个元组
acc = accuracy(neural_net(x_test),y_test)
if(epoch+1)%10 == 0: #每训练10次输出结果
print('Epoch [%d/%d],Train loss: %.3f,Test accuraccy: %.3f'%(epoch+1,EPOCHS,loss,acc))