CNN借用别人模型

import tensorflow as tf

import numpy as np

import matplotlib.pyplot as plt

import scipy

import keras

print(tf.config.list_physical_devices('GPU'))

设置GPU设备

gpus = tf.config.experimental.list_physical_devices('GPU')

try:

if gpus:

tf.config.experimental.set_visible_devices(gpus[0], 'GPU')

tf.config.experimental.set_memory_growth(gpus[0], True)

print("GPU set successfully!")

except Exception as e:

print(e)

rom keras.applications import VGG16

from keras.models import Model

from keras.layers import Dense, GlobalAveragePooling2D

include_top=False,因为后边有时间序列的网络,而序列一般是按水平摆放,

#所以这种不带时间序列的网络是竖起来放的,top层就是后边他们自己模型处理分类的那些层

我们只要他们前面抓几何图案的层,要全部设置好的系数,输入图形形状是(150,150,3)

base_model = VGG16(weights='imagenet', include_top=False,input_shape=(150,150,3))

#要估计的参数

#(9*3+1)*64,(9*64+1)*64,(9*64+1)*128,(9*128+1)*128,

#(9*128+1)*256,(9*256+1)*256,(9*256+1)*256,

#(9*256+1)*512,(9*512+1)*512,后面几层一样,input_deep

#output_deep都是512,使用的卷积是3x3,卷积层做了填充0

#使用的是最大池化,抓2x2中的最大数

#卷积神经网络通用的使用方法,滤镜越用越多个

#参数是14,714,688个,目前是可训练状态,后面我们要设为不可训练

#状态

base_model.summary()

from keras.utils import plot_model#画模型

#有向无环图,input,四维张量(样本数,某一层通道的宽,某层通道的高,层数)

plot_model(base_model,show_shapes=True,to_file='VGG16.png')

import os,shutil

from keras.preprocessing.image import ImageDataGenerator

basedir='../datasets/cats_dogs_s'

train_dir=os.path.join(basedir,'train')#训练数据文件夹

test_dir=os.path.join(basedir,'test')#测试数据文件夹

yz_dir=os.path.join(basedir,'yz')#验证数据文件夹

第一种方法,把数据过一下base_model(别人的模型),转化成特征图数据

batch_size=20#小批量的丢进去,每个批量20个样本

datagen=ImageDataGenerator(rescale=1./255)#把图片变成数据的生成器,rescale是最后把像素数据变成0-1之间

#提取特征方法,参数:要提取特征的文件夹,样本数

def extract_features(directory,ybs):

print('ybs:',ybs)

#初始化一个4维张量,4x4是滚过VGG16之后的图片大小,512是最后一层有512个神经元

#这个是存储特征图形的容器(2000,4,4,512)

features=np.zeros(shape=(ybs,4,4,512))

#初始化了一个一维张量,用来存放标签

#标签是用来分类的,0-猫,1-狗

labels=np.zeros(shape=(ybs))

这个方法处理后,图片就变成了4维张量数据,并被设置了y

#就是标签,你要读取的文件夹下有几类,标签就会设成几类

#类似0-猫,1-狗之类的,每个批次20个样本,设置的图片大小是(150,150)

#经过这个方法后,图片数据形状是(20,150,150,3),这个是个死循环

generator=datagen.flow_from_directory(

#读取的图片的文件夹

directory,

设置的图片大小

target_size=(150,150),

batch_size=batch_size,#每次生成20个图片数据

class_mode='binary'#二分类

)

i=0 #设置的标志位,遍历生成器,得到的是输入张量和输出标签

inputs_batch(20,150,150,3),labels_batch(20,)里面是0,1

for inputs_batch,labels_batch in generator:

经过这个处理后的特征图形是(20,4,4,512)

features_batch=base_model.predict(inputs_batch)

print('fetures_batch:',features_batch.shape)

i=99时,切片位置是[1980:2000],这个数把每次迭代的20个特征图

#数据放进容器,一次是放20个特征图,每个特征图是512层

features[i*batch_size:(i+1)*batch_size]=features_batch

这个是上面输入数据对应的标签,也就是y真实值

labels[i*batch_size:(i+1)*batch_size]=labels_batch

i+=1

i等于99就退出了

if i*batch_size>=ybs:

print('i:',i)

break

return features,labels

#经过别人模型处理的特征图和标签,特征图保留的是特别的几何图形,用来识别类别的

train_features,train_labels=extract_features(train_dir,2000)

yz_features,yz_labels=extract_features(yz_dir,1000)

test_features,test_labels=extract_features(test_dir,1000)

#变一下形,就是摊平,我们没用vgg16密集连接层,因为他们处理的是1000分类

train_features=train_features.reshape(2000,4*4*512)

yz_features=yz_features.reshape(1000,4*4*512)

test_features=test_features.reshape(1000,4*4*512)

print(np.max(train_features),np.min(train_features),np.argmax(train_features))

#VGG16处理后的特征图像素的最大值是10.988969802856445,最小值是0

a=train_features.reshape(-1)

print(a[13438107])

from keras import layers

from keras import models

from keras import optimizers

#第一种用别人模型的方法,只是用别人模型处理一下自己的数据,变成特征图

model=models.Sequential()

#隐藏层

model.add(layers.Dense(256,activation='relu',input_dim=4*4*512))

dropout层

model.add(layers.Dropout(0.5))

二分类问题,sigmoid,输出层

model.add(layers.Dense(1,activation='sigmoid'))

#我们自己要估计的参数(8192+1)*256,256+1,8192是摊平了

4*4*512

model.summary()

model.compile(optimizer=optimizers.RMSprop(learning_rate=1e-4),\

loss='binary_crossentropy',metrics=['acc'])

#loss: 0.1419 - acc: 0.9460 - val_loss: 0.2610 - val_acc: 0.8860

his=model.fit(train_features,train_labels,

epochs=20, # 训练轮数

verbose=2, # 日志显示模式

batch_size=20,

validation_data=(yz_features,yz_labels),

shuffle=True

)

#训练损失,验证损失,训练准确率,验证准确率

xl_loss=his.history['loss']

yz_loss=his.history['val_loss']

xl_acc=his.history['acc']

yz_acc=his.history['val_acc']

plt.rcParams['font.size'] = 22

plt.figure(figsize=(20,9),dpi=100)

plt.subplot((121))

#横坐标是迭代次数,纵坐标是损失

x=range(1,len(xl_loss)+1)

plt.plot(x,xl_loss,'b',label='xl_loss')

plt.plot(x,yz_loss,'bo',label='yz_loss')

plt.legend()

plt.subplot((122))

plt.plot(x,xl_acc,'r',label='xl_acc')

plt.plot(x,yz_acc,'ro',label='yz_acc')

plt.legend()

plt.show()

第二种用别人模型的方法,我们要增强数据,

就得把别人的前面处理几何图形的层都加进来

但不能动人家模型的参数

model_=models.Sequential()

model_.add(base_model)#别人模型的处理空间相关性的那些层

model_.add(layers.Flatten())#拍平特征图数据

model_.add(layers.Dense(256,activation='relu'))

model_.add(layers.Dropout(0.5))

二分类问题,sigmoid,输出层

model_.add(layers.Dense(1,activation='sigmoid'))

冻结之前,Non-trainable params: 0

model_.summary()

#冻结别人模型之前,要估计的层数,别人的13层+自己的2层,15层,有w和b两个,所以是30

print('冻结别人模型之前:',len(model_.trainable_weights))

#冻结别人模型

base_model.trainable=False

#之所以是4,可训练的层数,是因为我们自己加的就两层,每一层都要估计w和b两个张量,2*2=4

print('冻结别人模型之后:',len(model_.trainable_weights))

#冻结之后,模型参数,Non-trainable params: 14,714,688

model_.summary()

#增强数据

#因为训练准确率高,所以给训练增加难度,又是旋转

#又是平移,让电脑能抓住本质,fill_mode='nearest'是默认

train_datagen=ImageDataGenerator(

#图片数据*rescale设定值

rescale=1./255,

#旋转角度

rotation_range=40,

#平移

width_shift_range=0.2,

height_shift_range=0.2,

shear_range=0.2,

zoom_range=0.2,#放大缩小

#水平翻转

horizontal_flip=True

)

#验证资料就不要数据增强了,数据增强是为了让电脑抓到

#输入数据被贴上特定标签的本质原因,验证数据

是展示数据增强的成果的

yz_datagen=ImageDataGenerator(rescale=1./255)

train_datagen经历过图片平移,旋转之类的,增强训练难度

相当于我们在模拟考试前训练有些难度的题目

train_generator=train_datagen.flow_from_directory(

train_dir,

target_size=(150,150),

batch_size=20,

class_mode='binary'

)

yz_datagen只是把数据变到0-1,电脑喜欢小一些的浮点数据

vald_generator=yz_datagen.flow_from_directory(

yz_dir,

target_size=(150,150),

batch_size=20,

class_mode='binary'

)

learning_rate=1e-4,损失函数,二元交叉熵,衡量模型标准:准确率

model_.compile(optimizer=optimizers.RMSprop(learning_rate=5e-5),\

loss='binary_crossentropy',metrics=['acc'])

#loss: 0.3203 - acc: 0.8540 - val_loss: 0.2496 - val_acc: 0.8960

his_=model_.fit(train_generator,

epochs=30, # 训练轮数

verbose=2, # 日志显示模式

steps_per_epoch=100, # 每个epoch需要完成的步数,通常设置为训练集的总样本数除以批次大小

validation_data=vald_generator, # 如果有验证集的话,这里也应该是另一个DirectoryIterator实例

validation_steps=50, # 验证集的步数

shuffle=True

)

model_.compile(optimizer=optimizers.RMSprop(learning_rate=1e-5),\

loss='binary_crossentropy',metrics=['acc'])

#loss: 0.2657 - acc: 0.8850 - val_loss: 0.2505 - val_acc: 0.8970

model_.fit(train_generator,

epochs=20, # 训练轮数

verbose=2, # 日志显示模式

steps_per_epoch=100, # 每个epoch需要完成的步数,通常设置为训练集的总样本数除以批次大小

validation_data=vald_generator, # 如果有验证集的话,这里也应该是另一个DirectoryIterator实例

validation_steps=50, # 验证集的步数

shuffle=True

)

设置VGG16 block5_conv1层和之后的层可训练

base_model.trainable=True# 先设置VGG16所有层都可训练

set_trainable=False# 设个标志

for layer in base_model.layers:#遍历VGG16的层

if layer.name=='block5_conv1':# 如果是block5_conv1(它是Ture的话,它后边的层也会是True)

set_trainable=True

if set_trainable:# 标志是Ture,就把那层设为可训练

layer.trainable=True

else:# 否则设为不可训练

layer.trainable=False

自己的两层+VGG16的3层,5*2,w和b

print('设置之后:',len(model_.trainable_weights))

set_trainable之后,trainable params: 9,177,089,自己设置的(2097408+257),base_model的7079424

#和起来就是9177089

model_.summary()

model_.save('cats_and_dogs_small_32.h5')

如果按第二种添加别人模型的方法,而且自己训练的模型loss,acc都差不多

#的情况下,就可以解冻别人模型的block5_conv1之后得层,因为这些层

都多少是为他们自己的分类器设置系数了,我们这样设置后,就会更新这些层的系数

#learning_rate=1e-5微调就行

model_.compile(optimizer=optimizers.RMSprop(learning_rate=1e-5),\

loss='binary_crossentropy',metrics=['acc'])

#在开启别人的一些参数可训练之前,一定要已经

经过(base_model参数不可训练的)的模型训练差不多之后,参数不需要大幅度调整

#不然,反向传播会打乱别人模型里的增加的可调参数,达不到预期

loss: 0.0790 - acc: 0.9700 - val_loss: 0.2804 - val_acc: 0.9330

#有些时候val_acc和这个差不多,可是val_loss却非常大,都到1以上了,

#应该是学习率调的过大,搞坏了模型,但是为啥显示的验证准确率却很高呢,

#看那验证损失都1.5了.最好的模型应该是验证准确率和验证损失都比较小.

#而且训练准确率和训练损失也会和验证准确率和验证损失一致

#不能出现准确率显示很高,损失却很大的情况,如果出现说明学习率调大了

#搞坏了模型

history=model_.fit(train_generator,

epochs=30, # 训练轮数

verbose=2, # 日志显示模式

steps_per_epoch=100, # 每个epoch需要完成的步数,通常设置为训练集的总样本数除以批次大小

validation_data=vald_generator, # 如果有验证集的话,这里也应该是另一个DirectoryIterator实例

validation_steps=50, # 验证集的步数

shuffle=True

)

#在之前的30次epoch上继续微调

#loss: 0.0385 - acc: 0.9870 - val_loss: 0.2845 - val_acc: 0.9400

model_.compile(optimizer=optimizers.RMSprop(learning_rate=1e-5),\

loss='binary_crossentropy',metrics=['acc'])

history=model_.fit(train_generator,

epochs=20, # 训练轮数

verbose=2, # 日志显示模式

steps_per_epoch=100, # 每个epoch需要完成的步数,通常设置为训练集的总样本数除以批次大小

validation_data=vald_generator, # 如果有验证集的话,这里也应该是另一个DirectoryIterator实例

validation_steps=50, # 验证集的步数

shuffle=True

)

model_.save('cats_and_dogs_small_33.h5')#保存一下模型

#在之前的模型上继续调整,学习率调为5e-6,

#loss: 0.0248 - acc: 0.9895 - val_loss: 0.2841 - val_acc: 0.9540

#这是猫狗训练图片才2000张的情况下,准确率就已经95.4%,损失也不大

model_.compile(optimizer=optimizers.RMSprop(learning_rate=5e-6),\

loss='binary_crossentropy',metrics=['acc'])

history=model_.fit(train_generator,

epochs=20, # 训练轮数

verbose=2, # 日志显示模式

steps_per_epoch=100, # 每个epoch需要完成的步数,通常设置为训练集的总样本数除以批次大小

validation_data=vald_generator, # 如果有验证集的话,这里也应该是另一个DirectoryIterator实例

validation_steps=50, # 验证集的步数

shuffle=True

)

可以看到验证准确率最大出现在第20次epoch,而验证损失最小是出现在第8次epoch

print(np.max(history.history['val_acc']),np.argmax(history.history['val_acc']))

print(np.min(history.history['val_loss']),np.argmin(history.history['val_loss']))

xl_loss=history.history['loss']

yz_loss=history.history['val_loss']

xl_acc=history.history['acc']

yz_acc=history.history['val_acc']

plt.rcParams['font.size'] = 22

plt.figure(figsize=(20,9),dpi=100)

plt.subplot((121))

x=range(1,len(xl_loss)+1)

plt.plot(x,xl_loss,'b',label='xl_loss')

plt.plot(x,yz_loss,'bo',label='yz_loss')

plt.legend()

plt.subplot((122))

plt.plot(x,xl_acc,'r',label='xl_acc')

plt.plot(x,yz_acc,'ro',label='yz_acc')

plt.legend()

plt.show()

#经过指数平滑处理的图表,指数平滑EMA

def smth_(points,w=0.8):

#装平滑点的集合

smt_ps=[]

for point in points:

if not smt_ps:

print(smt_ps)

smt_ps.append(point)

else:

平滑点集合里的最后一个,就是上一个点

syg_ps=smt_ps[-1]

print('----',smt_ps)

smt_ps.append(w*syg_ps+(1-w)*point)

return smt_ps

xl_loss=smth_(history.history['loss'])

yz_loss=smth_(history.history['val_loss'])

xl_acc=smth_(history.history['acc'])

yz_acc=smth_(history.history['val_acc'])

plt.rcParams['font.size'] = 22

plt.figure(figsize=(20,9),dpi=100)

plt.subplot((121))

x=range(1,len(xl_loss)+1)

plt.plot(x,xl_loss,'b',label='xl_loss')

plt.plot(x,yz_loss,'bo',label='yz_loss')

plt.title('xl_loss,yz_loss')

plt.legend()

plt.subplot((122))

plt.plot(x,xl_acc,'r',label='xl_acc')

plt.plot(x,yz_acc,'ro',label='yz_acc')

plt.title('xl_acc,yz_acc')

plt.legend()

plt.show()

model_.save('./cats_and_dogs_small_36.h5')

test_generator=yz_datagen.flow_from_directory(

test_dir,

target_size=(150,150),

batch_size=20,

class_mode='binary'

)

#预测测试资料:test_loss,0.2628508508205414,test_acc,0.9449999928474426

test_loss,test_acc=model_.evaluate(test_generator,steps=50)

print('test_loss',test_loss)

print('test_acc',test_acc)

相关推荐
古希腊掌管学习的神1 小时前
[机器学习]XGBoost(3)——确定树的结构
人工智能·机器学习
ZHOU_WUYI1 小时前
4.metagpt中的软件公司智能体 (ProjectManager 角色)
人工智能·metagpt
靴子学长2 小时前
基于字节大模型的论文翻译(含免费源码)
人工智能·深度学习·nlp
AI_NEW_COME3 小时前
知识库管理系统可扩展性深度测评
人工智能
海棠AI实验室3 小时前
AI的进阶之路:从机器学习到深度学习的演变(一)
人工智能·深度学习·机器学习
hunteritself3 小时前
AI Weekly『12月16-22日』:OpenAI公布o3,谷歌发布首个推理模型,GitHub Copilot免费版上线!
人工智能·gpt·chatgpt·github·openai·copilot
IT古董4 小时前
【机器学习】机器学习的基本分类-强化学习-策略梯度(Policy Gradient,PG)
人工智能·机器学习·分类
centurysee4 小时前
【最佳实践】Anthropic:Agentic系统实践案例
人工智能
mahuifa4 小时前
混合开发环境---使用编程AI辅助开发Qt
人工智能·vscode·qt·qtcreator·编程ai
四口鲸鱼爱吃盐4 小时前
Pytorch | 从零构建GoogleNet对CIFAR10进行分类
人工智能·pytorch·分类