续上篇的shufflenet_v1,这里脚本基本没变,只是更改了网络模型文件shufflenet_v2.py
参考链接(详解):https://blog.csdn.net/u011995719/article/details/81409245
1.data_process.py(数据处理:这里随便选了两张照片,重复造数据,生成数据集)
import numpy as np
import random
import cv2
import os
import shutil
# path="data/train/"
# for file in os.listdir(path):
# file_name=path+file
# print(file_name)
# for i in range(100):
# new_file_name=path+file.split('.')[0]+"_"+str(i+1)+'.jpg'
# shutil.copy(file_name,new_file_name)
f1=open("data/train/data.txt",'w+')
path="data/train/"
for file in os.listdir(path):
file_name=path+file
print(file_name)
if file.endswith('jpg'):
f1.write(file+' '+file.split('.')[0].split('_')[0]+'\n')
2.train.py
import keras
from keras.preprocessing.image import ImageDataGenerator
from keras.applications.imagenet_utils import preprocess_input
from keras.utils import plot_model
from shufflenet import ShuffleNet
from shufflenetv2 import ShuffleNetV2
from keras.preprocessing.image import load_img
from keras.preprocessing import image
from keras.callbacks import CSVLogger, ModelCheckpoint, ReduceLROnPlateau, LearningRateScheduler
import numpy as np
import cv2
import time
import os
import utils
import tensorflow as tf
os.environ["CUDA_VISIBLE_DEVICES"] = "0"
config = tf.ConfigProto()
config.gpu_options.allow_growth=True #不全部占满显存, 按需分配
start=time.time()
#加载数据一
train_path='data/train/'
test_path='data/test/'
enhance_label=0
train_data,train_label=utils.load_dataset1(train_path,enhance_label)
test_data,test_label=utils.load_dataset1(test_path,enhance_label)
time=time.time()-start
print("加载数据耗时:",time)
log_dir='model/'
#接着上一次的echo继续训练
inital_epoch = 0
#append:True:如果文件存在则追加(对继续培训很有用);False:覆盖现有文件。 separator:元素分隔符
csv_logger = CSVLogger('log3.log', append=(inital_epoch is not 0))
# checkpoint = ModelCheckpoint(filepath='log3/m8.hdf5', verbose=0, save_best_only=True, monitor='val_acc', mode='max')
# #动态设置学习率,按照epoch的次数自动调整学习率
# learn_rates = [0.05, 0.01, 0.005, 0.001, 0.0005]
# lr_scheduler = LearningRateScheduler(lambda epoch: learn_rates[epoch // 30]) #每30个epoch改变一次学习率
checkpoint = ModelCheckpoint(log_dir + 'ep{epoch:03d}-loss{loss:.3f}-val_loss{val_loss:.3f}.h5',
monitor='val_loss', save_weights_only=False, save_best_only=True, period=5)
#调用shufflenet网络架构
model = ShuffleNetV2(groups=3, pooling='avg')
model.compile(
optimizer=keras.optimizers.Adam(lr=0.001, beta_1=0.9, beta_2=0.999, epsilon=None, decay=0.0),
metrics=['accuracy'], #评价指标
loss='categorical_crossentropy') #计算损失---分类交叉熵函数, binary_crossentropy(二分类)
# 训练方法二
models = model.fit(
train_data,
train_label,
batch_size=64,
epochs=5,
verbose=1,
shuffle=True,
callbacks=[csv_logger, checkpoint],
initial_epoch=0, #从指定的epoch开始训练,在这之前的训练时仍有用。
validation_split=0.1 #0~1之间,用来指定训练集的一定比例数据作为验证集
# validation_data=(test_data, test_label) #指定的验证集,此参数将覆盖validation_spilt。
)
#保存权重model.save_weights(),保存模型model.save()
model.save('m2.h5') #保存最后一次迭代的模型
model.save_weights('m1.h5')
# plt.plot(models.history['acc'])
# plt.plot(models.history['val_acc'])
# plt.title('Model accuracy')
# plt.ylabel('Accuracy')
# plt.xlabel('Epoch')
# plt.legend(['Train', 'Test'], loc='upper left')
# plt.show()
# plt.savefig('model2/plot1.jpg', format='jpg')
3.test.py
from shufflenet import ShuffleNet
from shufflenetv2 import ShuffleNetV2
from keras.preprocessing.image import load_img
from keras.preprocessing import image
from keras.applications.imagenet_utils import preprocess_input
from keras.models import load_model
import numpy as np
import utils
import keras
import os
import tensorflow as tf
model = ShuffleNetV2(groups=3, pooling='avg')
model.compile(
optimizer=keras.optimizers.Adam(lr=0.001, beta_1=0.9, beta_2=0.999, epsilon=None, decay=0.0),
metrics=['accuracy'],
loss='categorical_crossentropy')
model.load_weights('model/ep005-loss0.002-val_loss0.000.h5')
# model = load_model('model1/log1/m2.h5')
# 批量预测
path='E:/eye_dataset/test/eye/'
path2='data/test/'
acc=utils.get_acc(model,path2)
print("预测准确度:",acc)
# test_path='data2/test/'
# test_data,test_label=utils.load_dataset1(test_path,0)
# print(test_data.shape,test_label.shape)
# # 验证以及预测
# loss,acc=model.evaluate(test_data,test_label,verbose=1)
# print("验证集的损失为:",loss," 精度为:",acc)
3.shufflenetv2.py
#-*- coding:utf-8 -*-
#'''
# Created on 18-8-14 下午4:48
#
# @Author: Greg Gao(laygin)
#'''
import numpy as np
from keras.utils import plot_model
from keras_applications.imagenet_utils import _obtain_input_shape
from keras.engine.topology import get_source_inputs
from keras.layers import Input, Conv2D, MaxPool2D, GlobalMaxPooling2D, GlobalAveragePooling2D
from keras.layers import Activation, Add, Concatenate, Dense
from keras.layers import AveragePooling2D, BatchNormalization, Lambda, DepthwiseConv2D
from keras.models import Model
import keras.backend as K
import os
def ShuffleNetV2(include_top=True,
input_tensor=None,
scale_factor=1.0,
pooling='max',
input_shape=(224,224,3),
groups=1,
load_model=None,
num_shuffle_units=[3,7,3],
bottleneck_ratio=1,
classes=2):
if K.backend() != 'tensorflow':
raise RuntimeError('Only tensorflow supported for now')
name = 'ShuffleNetV2_{}_{}_{}'.format(scale_factor, bottleneck_ratio, "".join([str(x) for x in num_shuffle_units]))
input_shape = _obtain_input_shape(input_shape, default_size=224, min_size=28, require_flatten=include_top,
data_format=K.image_data_format())
out_dim_stage_two = {0.5:48, 1:116, 1.5:176, 2:244}
# 只允许两种池化方式
if pooling not in ['max', 'avg']:
raise ValueError('Invalid value for pooling')
# is_integer:判断是否是整形
if not (float(scale_factor)*4).is_integer():
raise ValueError('Invalid value for scale_factor, should be x over 4')
exp = np.insert(np.arange(len(num_shuffle_units), dtype=np.float32), 0, 0) # [0., 0., 1., 2.]
out_channels_in_stage = 2**exp
out_channels_in_stage *= out_dim_stage_two[bottleneck_ratio] # calculate output channels for each stage
out_channels_in_stage[0] = 24 # first stage has always 24 output channels
out_channels_in_stage *= scale_factor
out_channels_in_stage = out_channels_in_stage.astype(int)
if input_tensor is None:
img_input = Input(shape=input_shape)
else:
#判断是否是keras指定的数据类型,is_keras_tensor
if not K.is_keras_tensor(input_tensor):
img_input = Input(tensor=input_tensor, shape=input_shape)
else:
img_input = input_tensor
# 1.卷积+池化
x = Conv2D(filters=out_channels_in_stage[0], kernel_size=(3, 3), padding='same', use_bias=False, strides=(2, 2),
activation='relu', name='conv1')(img_input)
x = MaxPool2D(pool_size=(3, 3), strides=(2, 2), padding='same', name='maxpool1')(x)
# 2.Stage2、Stage3、Stage4
for stage in range(len(num_shuffle_units)):
repeat = num_shuffle_units[stage] #repeat=3/7/3
x = block(x, out_channels_in_stage,
repeat=repeat,
bottleneck_ratio=bottleneck_ratio,
stage=stage + 2)
if bottleneck_ratio < 2:
k = 1024
else:
k = 2048
# 3.卷积
x = Conv2D(k, kernel_size=1, padding='same', strides=1, name='1x1conv5_out', activation='relu')(x)
# 4.global_pool
if pooling == 'avg':
x = GlobalAveragePooling2D(name='global_avg_pool')(x)
elif pooling == 'max':
x = GlobalMaxPooling2D(name='global_max_pool')(x)
# 5.FC层
if include_top:
x = Dense(classes, name='fc')(x)
x = Activation('softmax', name='softmax')(x)
if input_tensor:
# get_source_inputs 返回计算需要的数据列表,List of input tensors
inputs = get_source_inputs(input_tensor)
else:
inputs = img_input
# 相当于tf的fit,喂入:inputs。输出:x 也可以输入输出多个参数:Model([x,y,z], [out_x,out_y])
model = Model(inputs, x, name=name)
if load_model:
model.load_weights('', by_name=True)
print('load_model.................')
return model
def channel_split(x, name=''):
# equipartition
in_channles = x.shape.as_list()[-1]
ip = in_channles // 2
c_hat = Lambda(lambda z: z[:, :, :, 0:ip], name='%s/sp%d_slice' % (name, 0))(x)
c = Lambda(lambda z: z[:, :, :, ip:], name='%s/sp%d_slice' % (name, 1))(x)
return c_hat, c
def channel_shuffle(x):
height, width, channels = x.shape.as_list()[1:]
channels_per_split = channels // 2
x = K.reshape(x, [-1, height, width, 2, channels_per_split])
x = K.permute_dimensions(x, (0,1,2,4,3))
x = K.reshape(x, [-1, height, width, channels])
return x
def shuffle_unit(inputs, out_channels, bottleneck_ratio,strides=2,stage=1,block=1):
if K.image_data_format() == 'channels_last':
bn_axis = -1
else:
raise ValueError('Only channels last supported')
# 第n个stage,第m个block (总共三个stage,分别3、7、3个block)
prefix = 'stage{}/block{}'.format(stage, block)
bottleneck_channels = int(out_channels * bottleneck_ratio)
if strides < 2:
c_hat, c = channel_split(inputs, '{}/spl'.format(prefix))
inputs = c
# 网络结构:线路2
x = Conv2D(bottleneck_channels, kernel_size=(1,1), strides=1, padding='same', name='{}/1x1conv_1'.format(prefix))(inputs)
x = BatchNormalization(axis=bn_axis, name='{}/bn_1x1conv_1'.format(prefix))(x)
x = Activation('relu', name='{}/relu_1x1conv_1'.format(prefix))(x)
x = DepthwiseConv2D(kernel_size=3, strides=strides, padding='same', name='{}/3x3dwconv'.format(prefix))(x)
x = BatchNormalization(axis=bn_axis, name='{}/bn_3x3dwconv'.format(prefix))(x)
x = Conv2D(bottleneck_channels, kernel_size=1,strides=1,padding='same', name='{}/1x1conv_2'.format(prefix))(x)
x = BatchNormalization(axis=bn_axis, name='{}/bn_1x1conv_2'.format(prefix))(x)
x = Activation('relu', name='{}/relu_1x1conv_2'.format(prefix))(x)
# 网络结构:线路1+Concat
if strides < 2:
ret = Concatenate(axis=bn_axis, name='{}/concat_1'.format(prefix))([x, c_hat])
else:
s2 = DepthwiseConv2D(kernel_size=3, strides=2, padding='same', name='{}/3x3dwconv_2'.format(prefix))(inputs)
s2 = BatchNormalization(axis=bn_axis, name='{}/bn_3x3dwconv_2'.format(prefix))(s2)
s2 = Conv2D(bottleneck_channels, kernel_size=1,strides=1,padding='same', name='{}/1x1_conv_3'.format(prefix))(s2)
s2 = BatchNormalization(axis=bn_axis, name='{}/bn_1x1conv_3'.format(prefix))(s2)
s2 = Activation('relu', name='{}/relu_1x1conv_3'.format(prefix))(s2)
ret = Concatenate(axis=bn_axis, name='{}/concat_2'.format(prefix))([x, s2])
# channel_shuffle
ret = Lambda(channel_shuffle, name='{}/channel_shuffle'.format(prefix))(ret)
return ret
# shuffle_unit: repeat1+repeat3 / repeat1+repeat7 / repeat1+repeat3
def block(x, channel_map, bottleneck_ratio, repeat=1, stage=1):
x = shuffle_unit(x, out_channels=channel_map[stage-1],
strides=2,bottleneck_ratio=bottleneck_ratio,stage=stage,block=1)
for i in range(1, repeat+1):
x = shuffle_unit(x, out_channels=channel_map[stage-1],strides=1,
bottleneck_ratio=bottleneck_ratio,stage=stage, block=(1+i))
return x
4.utils.py
from keras.applications.imagenet_utils import preprocess_input
from keras.preprocessing.image import load_img
from keras.preprocessing import image
import numpy as np
import random
import cv2
import os
def one_hot(data, num_classes):
return np.squeeze(np.eye(num_classes)[data.reshape(-1)])
# 限制学习率下标
def get_num(a):
if a>4:
a=4
return a
#预测结果返回0、1
def get_result(pre):
if pre[0][0]>pre[0][1]:
return 0
else:
return 1
def preprocess(x):
x = np.expand_dims(x, axis=0)
x = preprocess_input(x)
x /= 255.0
x -= 0.5
x *= 2.0
return x
def random_enhance(path,file): #随机颜色
img = cv2.imread(path+file)
img = cv2.resize(img, (224,224), interpolation=cv2.INTER_AREA)
# 1.图片随机裁剪
img = cv2.copyMakeBorder(img,8,8,8,8,cv2.BORDER_CONSTANT,value=(0,0,0)) #扩大填充黑色
upper_x = random.randint(0,16)
dowm_x =upper_x+224
upper_y = random.randint(0,16)
dowm_y = upper_y+224
image = img[upper_x:dowm_x,upper_y:dowm_y]
num1=random.randint(0,1)
# 2.随机翻转
if (num1==0):
image=cv2.flip(image, 1) #1:水平翻转 0:垂直翻转 -1:水平垂直翻转
img_hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
w=image.shape[0]
h=image.shape[1]
num2=random.randint(0,5)
# 1.hsv——色调
if (num2==0):
set_h = np.random.uniform(-3,8)
for i in range(w):
for j in range(h):
hsv_h=img_hsv[i,j][0]
hsv_h+=set_h
if hsv_h>255:
hsv_h=255
if hsv_h<0:
hsv_h=0
img_hsv[i,j][0]=hsv_h
image = cv2.cvtColor(img_hsv, cv2.COLOR_HSV2BGR)
# 2.hsv——饱和度
if (num2==1):
set_s = np.random.uniform(-30,30)
for i in range(w):
for j in range(h):
hsv_s=img_hsv[i,j][1]
hsv_s+=set_s
if hsv_s>255:
hsv_s=255
if hsv_s<0:
hsv_s=0
img_hsv[i,j][1]=hsv_s
image = cv2.cvtColor(img_hsv, cv2.COLOR_HSV2BGR)
# 3.hsv——亮度
if (num2==2):
set_v = np.random.uniform(-30,30)
for i in range(w):
for j in range(h):
v=img_hsv[i,j][2]
v+=set_v
if v>255:
v=255
if v<0:
v=0
img_hsv[i,j][2]=v
image = cv2.cvtColor(img_hsv, cv2.COLOR_HSV2BGR)
return image
#自己写的图片加载
def load_dataset1(path,enhance_label):
dataset = []
labels = []
f1=open(path+'data.txt','r')
for line in f1.readlines():
file_name=line.strip().split(' ')[0]
label=int(line.strip().split(' ')[-1])
# print(file_name,label)
if enhance_label==0:
# 1.原数据加载
pic=cv2.imread(path+file_name)
pic=cv2.resize(pic,(224,224), interpolation=cv2.INTER_CUBIC)
dataset.append(pic)
labels.append(label)
if enhance_label==1:
# 2.数据随机增强后加载
pic=random_enhance(path,file_name)
dataset.append(pic)
labels.append(label)
dataset=np.array(dataset)
labels=np.array(labels)
labels=one_hot(labels, 2)
return dataset, labels
#generator
def load_dataset2(path,enhance_label):
while 1:
dataset = []
labels = []
batch_size=64
f1=open(path+'data.txt','r')
lines=f1.readlines()
number=np.random.randint(0,len(lines),size=batch_size)
for i in range(batch_size):
num=number[i]
file_name=lines[num].strip().split(' ')[0]
label=int(lines[num].strip().split(' ')[-1])
# print(file_name,label)
if enhance_label==0:
# 1.原数据加载
pic=cv2.imread(path+file_name)
pic=cv2.resize(pic,(224,224), interpolation=cv2.INTER_CUBIC)
dataset.append(pic)
labels.append(label)
if enhance_label==1:
# 2.数据随机增强后加载
pic=random_enhance(path,file_name)
dataset.append(pic)
labels.append(label)
dataset=np.array(dataset)
labels=np.array(labels)
labels=one_hot(labels, 2)
yield dataset, labels
#按标签批量预测
def get_acc(model, path):
n=0
total=0
f1 = open(path + 'data.txt', 'r')
for line in f1.readlines():
total += 1
file_name=line.strip().split(' ')[0]
label=int(line.strip().split(' ')[-1])
# print(file_name,label)
img = load_img(path + file_name, target_size=(224, 224))
# img = image.img_to_array(img) / 255.0
img = np.expand_dims(img, axis=0)
predictions = model.predict(img)
result = get_result(predictions)
print("预测值为:", result,predictions,'---'+str(total))
if result==label:
n += 1
acc=n/total
print("准确度为:",acc)
return acc
# # 加载数据
# test_path='data2/test/'
# train_data_label=load_dataset2(test_path,1)