例一:我们有一个损失函数是(w+1)²,我们要找一个合适的w取值,让损失函数的值最小
import tensorflow as tf
w = tf.Variable(tf.constant(5, dtype=tf.float32)) #表明了哪个变量要进行优化
lr = 0.2 #梯度下降法中用到的α
epoch = 40 #表明要循环40次从而找到
for epoch in range(epoch): # for epoch 定义顶层循环,表示对数据集循环epoch次,此例数据集数据仅有1个w,初始化时候constant赋值为5,循环40次迭代。
with tf.GradientTape() as tape: # with结构到grads框起了梯度的计算过程。
loss = tf.square(w + 1) #定义这个损失函数
grads = tape.gradient(loss, w) # .gradient函数告知谁对谁求导,并
w.assign_sub(lr * grads) # .assign_sub 对变量做自减 即:w -= lr*grads 即 w = w - lr*grads
print("After %s epoch,w is %f,loss is %f" % (epoch, w.numpy(), loss))
一:基本概念和常见函数
(1)基本概念
张量的创建
import tensorflow as tf
(1) a=tf.constant([1,5],dtype=tf.int64) #这个张量是一阶张量,元素时1,5
(2)将numpy格式转化为tensor格式
a=np.arange(0,5)
b=tf.convert_to_tensor(a,dtype=tf.int64)
(3)采用不同函数创建不同值的张量
tf.zeros([2.3])
tf.ones(4)
tf.fill([2,2],9)
(4)采用不同函数创建符合不同分布的张量。
tf.random.normal(维度,mean=均值,stddev=标准差)生成正态分布的随机数,默认均值为0,标准差为1.
tf.random.truncated([2,2],mean=0.5,stddev=1) 生成截断式正态分布的随机数,能使生成的随机数更集中一些
tf.random.uniform([2.2],minval=0,maxval=1) 生成指定维度的均匀分布随机数,前闭后开区间
(2)常用函数
1.tf.cast(x1,tf.int32) 强制将张量x1的数据类型转换为tf.int32
2.tf.reduce_mean(张量名,axis=操作轴) 计算张量沿着指定维度的平均值 经纬度--》0为经度代表纵轴,1为维度代表横轴
tf.reduce_sum(张量名,axis=操作轴) 不指明axis的话就是对所有的元素进行操作
3.w=tf.Variable(tf.random.normal([2,2],mean=0,stddev=1)) 表明先随机生成正态分布随机数,再将生成的随机数标记为课训练,那么在反向传播中就可以通过梯度下降更新参数w了
4.利用Tensorflow函数对张量进行四则运算(只有维度相同的张量才可以一起进行运算)
tf.add(a,b)
tf.subtract(a,b)
tf.multiply(a,b)
tf.divide(b,a)
5.利用Tensorflow函数对张量进行幂次运算
tf.pow(a,3) 计算张量的3次方
tf.square(a) 计算张量a的平方
tf.sqrt(a) 计算张量a的开方
6.利用函数实现两个矩阵的相乘
tf.matmul(a,b)
7.可利用tf.data.Dataset.from_tensor_slices((输入特征,标签)),切分传入张量的第一维度,生成输入特征/标签对,构建数据集,此函数对Tensor格式和numpy格式均适用,。
features=tf.constant([12,23,10,17])
labels=tf.constant([0,1,1,0])
dataset=tf.data.Dataset.from_tensor_slices((features,labels))
print(dataset)
for element in dataset:
print(element) #可以发现一个输入特征和对应的一个标签成一队了
8.可利用tf.GradientTape()函数搭配with结构计算损失函数在某一张量处的梯度
with tf.GradientTape() as tape:
w=tf.Variable(tf.constant(3.0)) #这是我们要更新的变量
loss=tf.pow(w,2) #这是我们的损失函数
grad=tape.gradient(loss,w) #求出损失函数对于w的梯度
print(grad)
9.利用enumerate(列表名)函数枚举出每一个元素,并在元素前配上对应的索引号
seq=['one','two','three']
for i,element in enumerate(seq):
print(i,element)
10.可以用tf.one_hot(待转换数据,depth=几分类)函数实现用独热码表示标签。
classes=3
labels=tf.constant([1,0,2])
output=tf.one_hot(labels,depth=classes) #将labels数据看做是表示的3类(1,0,2每一个数代表一类)1可能是代表红色,0是白色,2是黑色都有可能,我们将分类转换成向量[1,0,0],[0,1,0],[0,0,1]表示3类数据
print(output) #此时输出是tf.Tensor([[0,1,0],[1,0,0],[0,0,1]])
11.可利用tf.nn.softmax()函数使前向传播的输出值符合概率分布,进而与独热码形式的标签作比较。比如说我们得到了前向传播的输出值 1.01,2.01,-0.66.我们现在要通过softmax函数对这些数进行处理,使得这些数能够表示概率概率,而这些数加起来正好为1
y=tf.constant([1.01,2.01,-0.66])
y_pro=tf.nn.softmax(y)
print("After softmax,y_pro is",y_pro)
12.可利用assign_sub函数对参数实现自更新。使用此函数前需要利用tf.Variable定义变量w为可训练(可自更新)
w=tf.Variable(4)
w.assign_sub(1)
print(w) #会实现参数w自减1
13.可以利用tf.argmax(张量名,axis=操作轴)返回张量沿指定维度最大值的索引
import numpy as np
test=np.array([[1,2,3],[2,3,4],[5,4,3],[8,7,2]])
print(tf.argmax(test,axis=0)) #返回每一列最大值的索引
print(tf.argmax(test,axis=1)) #返回每一行最大值的索引
14.tf.where(条件语句,A,B) 条件语句真返回A,假返回B
a=tf.constant([1,2,3,1,1])
b=tf.constant([0,1,3,4,5])
c=tf.where(tf.greater(a,b),a,b) #若a>b,返回a对应位置的元素,否则返回b对应位置的元素
15. np.random.RandomState.rand(维度)
会返回一个【0,1)之间的随机数
rdm=np.random.RandomState(seed=1)
a=rdm.rand()
b=rdm.rand(2,3) #这是一个两行三列的随机数矩阵
16. np.vstack(数组1,数组2) 将两个数组按垂直方向叠加
17.np.mgrid[起始值:结束值:步长,起始值:结束值:步长]
x.ravel() 将x变为一维数组
np.c_[数组1,数组2,...] 使返回的间隔数值点配对
import numpy as np
x,y=np.mgrid[1:3:1,2:4:0.5]
grid=np.c_[x.ravel(),y.ravel()]
print("x:",x)
print("y:",y)
print("grid:\n",grid) #通过这些函数可以完成网格点的设置
二:一些需要注意的地方
1.学习率:学习率是应用在梯度下降法中的一个超参数,设置的太大会引起震荡,太小会让优化进行的缓慢。这里我们有一个指数衰减学习率。可以先用较大的学习率来加快学习的速度,之后减少学习率,使模型在训练后期得以稳定。
指数衰减学习率=初始学习率*学习率衰减率的n次方 n=(当前轮数/多少轮衰减一次)
epoch=40
lr_base=0.2
lr_decay=0.99
lr_step=1
for epoch in range(epoch):
lr=lr_base*lr_decay**(epoch/lr_step)
with tf.GradientTape as tape:
loss=tf.square(w+1)
grads=tape.gradient(loss,w)
w.assign_sub(lr*grads)
print("After %s epoch,w is %f,loss is %f, lr is %f"%(epoch,w.numpy(),loss,lr))
三:程序实现咎尾花数据集分类
神经网络实现花的分类只需要三步
1.准备数据:包括数据集读入,数据集乱序,把测试集和训练集中的数据配成输入特征和标签对,生成train和test不重合的训练集和测试集
2.搭建网络:定义神经网络中的所有可训练参数
3.优化这些可训练的参数,利用嵌套循环在with结构中求得损失函数loss对每个可训练参数的偏导数,并更新这些可训练参数,为了查看效果,程序可以加入每遍历一遍数据集就显示当前准确率,还可以画出准确率acc和损失函数loss的变化曲线图
我们有150组数据,每组包括花的花萼长,花萼宽,花瓣长,花瓣宽四个输入特征,同时给出了这一组特征对应的花的类别。类别分别用0,1,2表示。
建立神经网络并运行的各个步骤代码如下
# 导入所需模块
import tensorflow as tf
from sklearn import datasets
from matplotlib import pyplot as plt
import numpy as np
# 导入数据,分别为输入特征和标签
x_data = datasets.load_iris().data
y_data = datasets.load_iris().target
# 随机打乱数据(因为原始数据是顺序的,顺序不打乱会影响准确率)
# seed: 随机数种子,是一个整数,当设置之后,每次生成的随机数都一样(为方便教学,以保每位同学结果一致)
np.random.seed(116) # 使用相同的seed,保证输入特征和标签一一对应
np.random.shuffle(x_data)
np.random.seed(116)
np.random.shuffle(y_data)
tf.random.set_seed(116)
# 将打乱后的数据集分割为训练集和测试集,训练集为前120行,测试集为后30行
x_train = x_data[:-30]
y_train = y_data[:-30]
x_test = x_data[-30:]
y_test = y_data[-30:]
# 转换x的数据类型,否则后面矩阵相乘时会因数据类型不一致报错
x_train = tf.cast(x_train, tf.float32)
x_test = tf.cast(x_test, tf.float32)
# from_tensor_slices函数使输入特征和标签值一一对应。(把数据集分批次,每个批次batch组数据)
train_db = tf.data.Dataset.from_tensor_slices((x_train, y_train)).batch(32)
test_db = tf.data.Dataset.from_tensor_slices((x_test, y_test)).batch(32)
# 生成神经网络的参数,4个输入特征故,输入层为4个输入节点;因为3分类,故输出层为3个神经元
# 用tf.Variable()标记参数可训练
# 使用seed使每次生成的随机数相同(方便教学,使大家结果都一致,在现实使用时不写seed)
w1 = tf.Variable(tf.random.truncated_normal([4, 3], stddev=0.1, seed=1))
b1 = tf.Variable(tf.random.truncated_normal([3], stddev=0.1, seed=1))
lr = 0.1 # 学习率为0.1
train_loss_results = [] # 将每轮的loss记录在此列表中,为后续画loss曲线提供数据
test_acc = [] # 将每轮的acc记录在此列表中,为后续画acc曲线提供数据
epoch = 500 # 循环500轮
loss_all = 0 # 每轮分4个step,loss_all记录四个step生成的4个loss的和
# 训练部分
for epoch in range(epoch): #数据集级别的循环,每个epoch循环一次数据集
for step, (x_train, y_train) in enumerate(train_db): #batch级别的循环 ,每个step循环一个batch
with tf.GradientTape() as tape: # with结构记录梯度信息
y = tf.matmul(x_train, w1) + b1 # 神经网络乘加运算
y = tf.nn.softmax(y) # 使输出y符合概率分布(此操作后与独热码同量级,可相减求loss)
y_ = tf.one_hot(y_train, depth=3) # 将标签值转换为独热码格式,方便计算loss和accuracy
loss = tf.reduce_mean(tf.square(y_ - y)) # 采用均方误差损失函数mse = mean(sum(y-out)^2)
loss_all += loss.numpy() # 将每个step计算出的loss累加,为后续求loss平均值提供数据,这样计算的loss更准确
# 计算loss对各个参数的梯度
grads = tape.gradient(loss, [w1, b1])
# 实现梯度更新 w1 = w1 - lr * w1_grad b = b - lr * b_grad
w1.assign_sub(lr * grads[0]) # 参数w1自更新
b1.assign_sub(lr * grads[1]) # 参数b自更新
# 每个epoch,打印loss信息
print("Epoch {}, loss: {}".format(epoch, loss_all/4))
train_loss_results.append(loss_all / 4) # 将4个step的loss求平均记录在此变量中
loss_all = 0 # loss_all归零,为记录下一个epoch的loss做准备
# 测试部分
# total_correct为预测对的样本个数, total_number为测试的总样本数,将这两个变量都初始化为0
total_correct, total_number = 0, 0
for x_test, y_test in test_db:
# 使用更新后的参数进行预测
y = tf.matmul(x_test, w1) + b1
y = tf.nn.softmax(y)
pred = tf.argmax(y, axis=1) # 返回y中最大值的索引,即预测的分类
# 将pred转换为y_test的数据类型
pred = tf.cast(pred, dtype=y_test.dtype)
# 若分类正确,则correct=1,否则为0,将bool型的结果转换为int型
correct = tf.cast(tf.equal(pred, y_test), dtype=tf.int32)
# 将每个batch的correct数加起来
correct = tf.reduce_sum(correct)
# 将所有batch中的correct数加起来
total_correct += int(correct)
# total_number为测试的总样本数,也就是x_test的行数,shape[0]返回变量的行数
total_number += x_test.shape[0]
# 总的准确率等于total_correct/total_number
acc = total_correct / total_number
test_acc.append(acc)
print("Test_acc:", acc)
print("--------------------------")
# 绘制 loss 曲线
plt.title('Loss Function Curve') # 图片标题
plt.xlabel('Epoch') # x轴变量名称
plt.ylabel('Loss') # y轴变量名称
plt.plot(train_loss_results, label="$Loss$") # 逐点画出trian_loss_results值并连线,连线图标是Loss
plt.legend() # 画出曲线图标
plt.show() # 画出图像
# 绘制 Accuracy 曲线
plt.title('Acc Curve') # 图片标题
plt.xlabel('Epoch') # x轴变量名称
plt.ylabel('Acc') # y轴变量名称
plt.plot(test_acc, label="$Accuracy$") # 逐点画出test_acc值并连线,连线图标是Accuracy
plt.legend()
plt.show()
补充:如果花的数据集在本地文件中,我们还需要从本地中读取数据集的txt文件,并将其输入到神经网络进行训练
txt文件如下
"Sepal.Length""Sepal.Width""Petal.Length""Petal.Width""Species"
"1"5.1 3.5 1.4 0.2 "setosa"
"2"4.9 3 1.4 0.2 "setosa"
1.通过pandas函数读取,并处理成神经网络需要的数据结构
df=pd.read_csv('iris.txt',header=None,sep=',')
data=df.values
x_data=[lines[0:4]for lines in data] #取输入特征
x_data=np.array(x_data,float) #转换为numpy格式
y_data=[lines[4]for lines in data] #取标签
for i in range(len(y_data)):
if y_data[i]=='iris-setosa':
y_data[i]=0
elif y_data[i]=='iris-versicolor':
y_data[i]=1
......
y_data=np.array(y_data)
2.通过open函数打开txt文件,并处理成神经网络需要的数据结构
f=open("iris.txt","r")
contents=f.readlines()
i=0
for content in contents:
temp=content.split(',')
x_data[i]=np.array([temp[0:4]],dtype=float)
if temp[4]=="Iris-setosa\n":
y_data[i]=0
elif temp[4]="Iris-versicolor\n":
y_data[i]=1
.....
i=i+1
四:用tf.keras搭建网络八股
3.1 搭建网络的步骤如下
(1)import 相应的模块
(2)指定输入网络的训练集和测试集
(3)逐层搭建网络结构 mdoel=tf.keras.models.Sequential()
(4)在 model.compile()中配置训练方法,选择训练时使用的优化器,损失函数和最终评价指标
(5)在model.fit()中执行训练过程,告知训练集和测试集中的输入值和标签
(6)使用model.summary()打印网络结构,统计参数数目
3.2 涉及到的函数
1.tf.keras.models.Sequential
Sequential函数是一个容器,描述了神经网络的网络结构,在Sequential函数中的输入参数中描述从输入层到输出层中的网络结构
tf.keras.layers.Dense(神经元个数,activation="激活函数",kernel_regularizer="正则化方式")
activation可选relu,softmax,sigmoid,tanh等; kernel_regularizer可选 tf.keras.regularizers.l1() tf.keras.regularizers.l2()
2.compile用来配置神经网络的训练方法,告知训练时使用的优化器,损失函数和准侧率评测标准
Model.compile(optimizer=优化器,loss=损失函数,metrics=["准确率"])
optimizer来设置优化器时可以用字符串来设定,也可以用函数形式来设定。用字符串的话一些超参数只能用默认设置,用函数形式的话可以自己手动设置
‘sgd’ tf.optimizers.SGD(lr=学习率,decay=学习率衰减率,momentum=动量参数)
‘adagrad’ tf.keras.optimizers.Adagrad(lr=学习率,decay=学习率衰减率)
‘adadelta’ tf.keras.optimizers.Adadelta(lr=学习率,decay=学习率衰减率)
‘adam’ tf.keras.optimizers.Adam(lr=学习率,decay=学习率衰减率)
loss可以是字符串也可以是函数形式
可选项包括如下:
‘mse’ or tf.keras.losses.MeanSquaredError()
‘sparse_categorical_crossentropy’ or tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False)
from_logits参数是说明是否要直接输出结果,False的话就要用softmax等函数将输出转化为概率分布的形式。
metrics 标注网格评测指标
可选项包括:
‘accrracy’:那么y_和y都是数值 y是指我们经过神经网络的输出,y_是指我们的标签数值
'categorical_accuracy' :y_和y都是以独热码和概率分布表示
‘sparse_categorical_accuracy’:y_是以数值形式给出,y是以独热码形式给出
3.model.fit(训练集的输入特征,训练集的标签,batch_size,epochs,validation_data=(测试集的输入特征,测试集的标签),validation_split=从测试集中划分多少比例给训练集,validation_freq=测试的epoch间隔次数)
fit函数用来执行训练过程
4.model.summary()
summary函数用来打印网络结构和参数统计
3.3 用keras来实现之前的花的分类
第一步:import相关模块
import tensorflow as tf
from sklearn import datasets
import numpy as np
第二步:指定输入网络的训练集和测试集
x_train=datasets.load_iris().data
y_train=datasets.load_iris().target
np.random.seed(116)
np.random.shuffle(x_train)
np.random.seed(116)
np.random.shuffle(y_train)
tf.random.set_seed(116)
第三步:逐层搭建网络结构
model=tf.keras.models.Sequential([tf.keras.layers.Dense(3,activation='softmax',kernel_regularizer=tf.keras.regularizers.12())])
#此时使用了单层全连接网络,第一个参数表示神经元个数,第二个参数表示网络所使用的激活函数,第三个参数表示选用的正则化方法
表示网络结构还可以用class来声明
class MyModel(Model): #括号里的Model表示创建的类要继承TensorFlow库中的Model类。
def__init__(self): #__init__函数定义所需的网络结构块
super(MyModel,self).__init__() #表示初始化父类的参数。之后就可以初始化网络结构,搭建出神经网络所需的各种网络结构块
定义网络结构块
def call(self,x): #写出前向传播
y=self.d1(x) #call函数中调用__init__函数完成初始化的网络块,调用网络结构块实现前向传播
return y
model=MyModel()
以上是class声明网络结构的基本格式,下面我们用class来声明识别花的网络的结构
class IrisModel(Model):
def __init__(self):
super(IrisModel,self).__init__()
self.d1=Dense(3,activation='sigmoid',kernel_regularizer=tf.keras.regularizers.l2()) #d1是给这一层起的名字
def call(self,x):
y=self.d1(x)
return y
之后只要使用Model=MyModel()构建类的对象,就可以使用该模型了。
第四步:在model.compile()中配置训练方法
model.compile(optimizer=tf.keras.optimizers.SGD(lr=0.1),loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False,metrics=['sparse_categorical_accuracy']))
#使用了SGD优化器,学习率设置为0.1,选择SparseCategoricalCrossentrop作为损失函数。由于神经网络是用来softmax激活函数,使得输出是概率分布而不是原始输出,所以将from_logits参数设置为False。因为花的数据集的标签是0,1,2这样的数值,而网络前向传播的输出为概率分布,所以metrics需要设置为sparse_categorical_accuracy
第五步:model.fit()执行训练过程
model.fit(x_train,y_train,batch_size=32,epochs=500,validation_split=0.2,validation_freq=20)
#在fit中执行训练过程,validation_split表示数据集中测试集的划分比例,validation_freq表示每迭代20次在测试集中测试一次准确率。
第六步:使用model.summary()打印网络结构,统计参数数目
model.summary()
完整代码如下
import tensorflow as tf
from tensorflow.keras.layers import Dense
from tensorflow.keras import Model
from sklearn import datasets
import numpy as np
x_train=datasets.load_iris().data
y_train=datasets.load_iris().target
np.random.seed(116)
np.random.shuffle(x_train)
np.random.seed(116)
np.random.shuffle(y_train)
tf.random.set_seed(116)
class IrisModel(Model):
def __init__(self):
super(IrisModel,self).__init__()
self.d1=Dense(3,activation="softmax",kernel_regularizer=tf.keras.regularizers.l2())
def call(self,x):
y=self.d1(x)
return y
model=IrisModel()
model.compile(optimizer=tf.keras.optimizers.SGD(lr=0.1),
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False),
metrics=['sparse_categorical_accuracy'])
model.fit(x_train,y_train,batch_size=32,epochs=500,validation_split=0.2,validation_freq=20)
model.summary()
为了掌握六步法建立并训练神经网络,我们引入了两个数据集,运用神经网络去模拟数据
例一:MNIST数据集
这个数据集一共有7万张图片,28*28的0到9手写数字数据集,其中6万张用来训练,1万张用来测试。
我们建立一个神经网络用来识别图片并判断出来图片上的数字是啥
#1.导入模块
import tensorflow as tf
#2.指定训练集和测试集
mnist = tf.keras.datasets.mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0
#3.搭建网络结构
model = tf.keras.models.Sequential([
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dense(10, activation='softmax')
])
#4.配置训练方法
model.compile(optimizer='adam',
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False),
metrics=['sparse_categorical_accuracy'])
#5.执行训练
model.fit(x_train, y_train, batch_size=32, epochs=5, validation_data=(x_test, y_test), validation_freq=1)
#6.打印网络结构,统计参数数量
model.summary()
例二:Fashion_mnist数据集
包括6万张训练图片和1万张测试图片,图片被分为10类,每张图像为28*28的分辨率。(1代表T恤,2代表裤子等)
1.导入库
import tensorflow as tf
from tensorflow.keras.layers import Dense, Flatten
from tensorflow.keras import Model
2.指定训练集和测试集
fashion = tf.keras.datasets.fashion_mnist
(x_train, y_train),(x_test, y_test) = fashion.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0
3.设计网络结构
class MnistModel(Model):
def __init__(self):
super(MnistModel, self).__init__()
self.flatten = Flatten()
self.d1 = Dense(128, activation='relu')
self.d2 = Dense(10, activation='softmax')
def call(self, x):
x = self.flatten(x)
x = self.d1(x)
y = self.d2(x)
return y
model = MnistModel()
4.设置网络优化方式
model.compile(optimizer='adam',
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False),
metrics=['sparse_categorical_accuracy'])
5.进行训练
model.fit(x_train, y_train, batch_size=32, epochs=5, validation_data=(x_test, y_test), validation_freq=1)
6.打印网络结构
model.summary()
五:八股树的扩展
1.自制数据集,解决本领域的应用
2.数据增强,扩增数据集
3.断点续训,保存模型
4.参数提取,把参数存在文本中
5.acc、loss可视化,查看训练效果
6.应用程序,给物识图
5.1 自制数据集,解决本领域的应用
我们之前读取数据集是从自带的数据包中读取的所以代码很简单,(x_train,y_train),(x_test,y_test)=fashion.load_data()。那么如果我们的数据集是以文本文件的形式存放在电脑中,我们又该怎么读取呢。
import tensorflow as tf
from PIL import Image
import numpy as np
import os
train_path = './mnist_image_label/mnist_train_jpg_60000/'
train_txt = './mnist_image_label/mnist_train_jpg_60000.txt'
x_train_savepath = './mnist_image_label/mnist_x_train.npy'
y_train_savepath = './mnist_image_label/mnist_y_train.npy'
test_path = './mnist_image_label/mnist_test_jpg_10000/' #这个文件夹中存放着测试集数据
test_txt = './mnist_image_label/mnist_test_jpg_10000.txt' #这个txt文件中存放着图片的名字和对应的标签
x_test_savepath = './mnist_image_label/mnist_x_test.npy' #测试集特征存储文件
y_test_savepath = './mnist_image_label/mnist_y_test.npy' #测试集标签存储文件
def generateds(path, txt): #path是txt文件所在的文件夹文职,txt是这个文件的名字
f = open(txt, 'r') # 以只读形式打开txt文件
contents = f.readlines() # 读取文件中所有行
f.close() # 关闭txt文件
x, y_ = [], [] # 建立空列表
#txt文件中被空格分为两部分,图片名称和标签
for content in contents: # 逐行取出
value = content.split() # 以空格分开,图片路径为value[0] , 标签为value[1] , 存入列表
img_path = path + value[0] # 拼出图片路径和文件名
img = Image.open(img_path) # 读入图片
img = np.array(img.convert('L')) # 图片变为8位宽灰度值的np.array格式
img = img / 255. # 数据归一化 (实现预处理)
x.append(img) # 归一化后的数据,贴到列表x
y_.append(value[1]) # 标签贴到列表y_
print('loading : ' + content) # 打印状态提示
x = np.array(x) # 变为np.array格式
y_ = np.array(y_) # 变为np.array格式
y_ = y_.astype(np.int64) # 变为64位整型
return x, y_ # 返回输入特征x,返回标签y_
if os.path.exists(x_train_savepath) and os.path.exists(y_train_savepath) and os.path.exists(
x_test_savepath) and os.path.exists(y_test_savepath): #如果我们曾经读取过文件并将读取结果以.npy文件的形式保存就执行以下代码
print('-------------Load Datasets-----------------')
x_train_save = np.load(x_train_savepath)
y_train = np.load(y_train_savepath)
x_test_save = np.load(x_test_savepath)
y_test = np.load(y_test_savepath)
x_train = np.reshape(x_train_save, (len(x_train_save), 28, 28))
x_test = np.reshape(x_test_save, (len(x_test_save), 28, 28))
else:
print('-------------Generate Datasets-----------------')
x_train, y_train = generateds(train_path, train_txt) #调用上面书写的函数读取数据,并将数据变成训练集和对应的标签这样的形式
x_test, y_test = generateds(test_path, test_txt)
print('-------------Save Datasets-----------------')
x_train_save = np.reshape(x_train, (len(x_train), -1)) #我们将得到的训练集重新定义形状,此时会让行向量变成列向量
x_test_save = np.reshape(x_test, (len(x_test), -1))
np.save(x_train_savepath, x_train_save) #我们将这个训练集在事先声明好的路径下保存
np.save(y_train_savepath, y_train)
np.save(x_test_savepath, x_test_save)
np.save(y_test_savepath, y_test)
5.2 数据增强
如果数据集元素不够的话,可以进行数据增强从而实现数据集的扩充。
image_gen_train=tf.keras.preprocessing.image.ImageDataGenerator(
rescale=所有数据将乘以提供的值 缩放系数
rotation_range=随机旋转角度数范围 随机旋转
width_shift_range=随机宽度偏移量 宽度偏移
height_shift_range=随机高度偏移量 高度偏移
horizontal_flip=是否水平随机翻转 水平翻转
zoom_range=随机缩放的范围 随机缩放 [1-n,1+n]
)
image_gen_train.fit(x_train)
eg:在之前识别花的类别的例子中用这个来扩增数据,有几个地方要在原来基础上修改
1.导入新的模块 from tensorflow.keras.preprocessing.image import ImageDataGenerator
2.规定对数据进行扩增的操作
image_gen_train=ImageDataGenerator(
rescale=1./255, #原像素值0-255归到0-1
rotation_range=45, #随机45度旋转
width_shift_range=.15, #随机宽度偏移【-0.15,0.15)
height_shift_range=.15, #随机高度偏移【-0.15,0.15)
horizontal_flip=True, #随机水平翻转
zoom_range=0.5 #随机缩放到【1-50%,1+50%】
)
image_gen_train.fit(x_train)
3.我们的image_gen_train.fit()里面只能放4维数据,所以我们要先将x_train进行reshape
x_train=x_train.reshape(x_train.shape[0],28,28,1)
4.此时我们的训练数据的代码也要修改
原来是 model.fit(x_train,y_train,batch_size=32,....)
应用了数据增强后要变成 model.fit(image_gen_train.flow(x_train,y_train,batch_size=32),.....)
5.3 断点续训,存取模型
(1)读取模型
checkpoint_save_path="./checkpoint/mnist.ckpt" #我们将模型都会存在ckpt文件中
if os.path.exists(checkpoint_save_path+'.index'): #我们如果存储过模型,那么会自动生成一个索引文件,所以我们通过判断这个文件是否存在来判断是否存储过模型
model.load_weights(checkpoint_save_path)
(2)保存模型
#借助tensorflow提供的回调函数,直接保存参数和网络
tf.keras.callbacks.ModelCheckpoint(
filepath=路径文件名,
save_weights_only=True,
monitor="val_loss",
save_best_only=True)
history=model.fit(x_train,y_train,batch_size=32,epochs=5,validation_data=(x_test,y_test),validation_freq=1,callbacks=[cp_callback])
5.4 参数提取,写至文本
在上一步中保存的参数,在这里我们将其提取出来
提取可训练参数:model.trainable_variables 模型中可训练的参数
设置print输出格式:np.set_printoptions(precision=小数点后按四舍五入保留几位,threshold=数组元素数量少于或等于门槛值,打印全部元素,否则打印门槛值+1个元素,中间用省略值补充) 我们给precision=np.inf时就会打印全部的小数位,给threshold=np.nan时就会打印全部的数组元素。
完整代码如下:
import tensorflow as tf
import os
import numpy as np
np.set_printoptions(threshold=np.inf)
mnist = tf.keras.datasets.mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0
model = tf.keras.models.Sequential([
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dense(10, activation='softmax')
])
model.compile(optimizer='adam',
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False),
metrics=['sparse_categorical_accuracy'])
checkpoint_save_path = "./checkpoint/mnist.ckpt"
if os.path.exists(checkpoint_save_path + '.index'):
print('-------------load the model-----------------')
model.load_weights(checkpoint_save_path)
cp_callback = tf.keras.callbacks.ModelCheckpoint(filepath=checkpoint_save_path,
save_weights_only=True,
save_best_only=True)
history = model.fit(x_train, y_train, batch_size=32, epochs=5, validation_data=(x_test, y_test), validation_freq=1,
callbacks=[cp_callback])
model.summary()
print(model.trainable_variables)
file = open('./weights.txt', 'w')
for v in model.trainable_variables:
file.write(str(v.name) + '\n')
file.write(str(v.shape) + '\n')
file.write(str(v.numpy()) + '\n')
file.close()
5.5 acc/loss可视化,查看效果
其实在我们的history=model.fit()执行训练时中已经把训练集loss,测试集loss,训练集准确率,测试集准确率记录了下来。我们这时通过history将这些信息提取出来
import matplotlib.pyplot as plt
#history中读取所需的数据
acc=history.history['sparse_categorical_accuracy'] #训练集准确度
val_acc=history.history['val_sparse_categorical_accuracy'] #测试集准确度
loss=history.history['loss'] #训练集误差
val_loss=history.history['val_loss'] #测试集误差
#画图
plt.figure(figsize=(8,8))
plt.subplot(1,2,1)
plt.plot(acc,label='Training Accuracy')
plt.plot(val_acc,label='Validatioin Accuracy')
plt.title('Training and Validation Accuracy')
plt.legend()
plt.subplot(1,2,2)
plt.plot(loss,label="Training loss")
plt.plot(val_loss,label='Validation loss')
plt.title('Training and validation loss')
plt.legend()
plt.show()
5.6 应用程序,绘物识图
我们之前训练好了神经网络可以进行识别图片中的数字。那么我们此时有个图片,如何给神经网络让它进行识别呢。
from PIL import Image
import numpy as np
import tensorflow as tf #导入所需的模块
model_save_path = './checkpoint/mnist.ckpt' #这是存放我们训练好的神经网络模型的文件位置
model = tf.keras.models.Sequential([ #设置神经网络的格式
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dense(10, activation='softmax')])
model.load_weights(model_save_path) #读取训练好的神经网络的参数值
preNum = int(input("input the number of test pictures:")) #确定读取的图片数量
for i in range(preNum):
image_path = input("the path of test picture:")
img = Image.open(image_path)
img = img.resize((28, 28), Image.ANTIALIAS) #训练模型时是28*28的灰度图,而现在是任意尺度的图片,所以我们要resize一下
img_arr = np.array(img.convert('L'))
for i in range(28): #我们训练模型是用灰度图,而现在是用白底黑字的图,所以要对数据进行预处理
for j in range(28):
if img_arr[i][j] < 200: #暗的地方调亮,变成纯白色
img_arr[i][j] = 255
else:
img_arr[i][j] = 0
img_arr = img_arr / 255.0
x_predict = img_arr[tf.newaxis, ...] #神经网络训练时,都是一个batch进入网络的,所以我们要添加一个维度,从28*28---》1*28*28
result = model.predict(x_predict) #使用predict函数执行前向传播从而得到计算结果
pred = tf.argmax(result, axis=1)
print('\n')
tf.print(pred)