采用DensNet121模型进行迁移学习——服装二分类任务

这是一个品牌分类任务,需要设计一个神经网络,识别出其正确率。采用DensNet121进行迁移学习。

from sklearn import metrics
import numpy as np
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import Model, layers
from tensorflow.keras import layers, optimizers, datasets, Sequential
import os  
from tensorflow.python.keras import regularizers

# 数据读取函数,返回训练集、验证集、测试集

def get_data(height, width, batchsz):
    # 获取训练集
    filepath1 = '/content/drive/MyDrive/Colab Notebooks/Fashion_Dataset/train'
    train_ds = tf.keras.preprocessing.image_dataset_from_directory(
        filepath1,         # 指定数据路径
        label_mode='categorical', # 导入的目标数据,进行onehot编码
        image_size=(height, width), # 对图像resize
        batch_size=batchsz, # 每次迭代的batchsize
    )

    # 获取验证集数据
    filepath2 = '/content/drive/MyDrive/Colab Notebooks/Fashion_Dataset/val'
    val_ds = tf.keras.preprocessing.image_dataset_from_directory(
        filepath2,  
        label_mode='categorical',
        image_size=(height, width),  
        batch_size=batchsz, 
    )

    # 获取验证集数据
    filepath3 = '/content/drive/MyDrive/Colab Notebooks/Fashion_Dataset/test'
    test_ds = tf.keras.preprocessing.image_dataset_from_directory(
        filepath3, 
        label_mode='categorical',  
        image_size=(height, width), 
        batch_size=batchsz,  
    )

    return (train_ds, val_ds, test_ds)

# 获取数据
train_ds, val_ds, test_ds = get_data(224, 224, 64) 
# 查看分类名称
class_names = train_ds.class_names
print('分类名:', class_names)
# 查看数据信息
sample = next(iter(train_ds))
print('x_batch.shape:', sample[0].shape, 'y_batch.shape:', sample[1].shape)
# 构建归一化函数
def processing(x, y):
    # 图像中的每个像素值映射到[-1,1]之间 归一化
    x = 2 * tf.cast(x, dtype=tf.float32) / 255.0 - 1
    y = tf.cast(y, dtype=tf.int32)
    # 返回处理后的结果
    return (x, y)
#对数据进行洗牌
train_ds = train_ds.map(processing).shuffle(10000)
val_ds = val_ds.map(processing)  # 验证集和测试集不需要打乱顺序
test_ds = test_ds.map(processing)
# 查看数据信息
sample = next(iter(train_ds))
print('x_batch.shape:', sample[0].shape, 'y_batch.shape:', sample[1].shape)

#载入DensNet模型并进行网络微调
def get_new_model():
  pre_model = tf.keras.applications.DenseNet121(
    # 不包括全连接层,导入预训练权重,自定义输入图片大小
    include_top=False, weights='imagenet', input_shape=[224, 224, 3]
    )

  # 冻住特征提取层
  for layer in pre_model.layers:
    # 正反向传播过程中权重参数不更新
    layer.trainable = False  

  # 进行一次前向传播,看图像有何改变
  imgs, labels = next(iter(train_ds))  

  # 获取训练集的某一个batch的图像及标签
  res = pre_model(imgs)

 
  # 微调网络
  # 解冻所有网络层
  pre_model.trainable = True
  print('numbers of layers:', len(pre_model.layers))
  # 查看一共有多少层:780

  # 指定冻结前500层 
  find_tune_at = 500  

  # 前500层在正方向传播过程中参数不能变,剩下的层权重参数可以调整
  for layer in pre_model.layers[:find_tune_at]:  # 包括第500层
    layer.trainable = False
# 构造输出层
  # 对特征提取层的输出进行全局平均池化
  x = layers.GlobalAveragePooling2D()(pre_model.output)
  x = layers.Flatten(name='flatten')(x)
  x = layers.Dense(2048, activation='relu', kernel_regularizer=regularizers.l2(0.0001))(x) #对数据进行正则化
  x = layers.BatchNormalization()(x)
  x = layers.Dense(1024, activation='relu', kernel_regularizer=regularizers.l2(0.0001))(x)
  x = layers.BatchNormalization(name='bn_fc_01')(x)
  
  #输出层分2类
  x = layers.Dense(2, activation='softmax')(x) 

  # 构建模型
  model = Model(pre_model.input, x)

  #网络配置,调小学习率避免过拟合
  opt = optimizers.Adam(learning_rate=0.001) 

  #编译
  model.compile(optimizer=opt,  # 学习率
       loss='categorical_crossentropy',  # 对onehot后的y,计算交叉熵损失
       metrics=['accuracy'])  # 评价指标

  return model

model = get_new_model()
model.summary()

from tensorflow.keras.callbacks import ModelCheckpoint

checkpoint_path = '/content/drive/MyDrive/model_checkpoints'  # 每次保存的都会覆盖旧的
# 每次保存为一个新的文件
checkpoint = ModelCheckpoint(filepath=checkpoint_path,
                             save_freq='epoch',   # 每个epoch结束就保存一次
                             save_weights_only=True,
                             verbose=1)   

# 训练,在上一次训练的基础上继续训练10次
history_fine = model.fit(train_ds,  # 训练集
              validation_data=val_ds,  # 验证集
              epochs=25,
              callbacks=[checkpoint])  # 迭代次数修改epoch

import matplotlib.pyplot as plt
train_acc = history_fine.history['accuracy']
test_acc = history_fine.history['val_accuracy']
# 损失
train_loss = history_fine.history['loss']
test_loss = history_fine.history['val_loss']
# 绘图
# 准确率曲线
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
plt.plot(train_acc, label='train_acc')
plt.plot(test_acc, label='test_acc')
plt.title('accuracy')
plt.legend() #显示图例label
# 损失曲线
plt.subplot(1, 2, 2)
plt.plot(train_loss, label='train_loss')
plt.plot(test_loss, label='test_loss')
plt.title('loss')
plt.legend()
plt.show()
test_loss, test_acc =model .evaluate(test_ds)
print("Test loss: {:.3f}\nTest accuracy: {:.2f}%".format(test_loss, 100 * test_acc))

利用K折交叉熵

from PIL import Image

# 从文件夹读取图片和标签到numpy数组中
# 标签信息在文件名中,burberry类型的衣服表示该图片的标签为0
def read_data(data_dir):
  datas = []
  labels = []
  
  for fname in os.listdir(data_dir):
    if fname[:8] =='burberry':
      label = 0
    else:
      label = 1
    
    fpath = os.path.join(data_dir, fname)
    i=0
    for ffname in os.listdir(fpath):
      ffpath = os.path.join(fpath, ffname)
      
      image = Image.open(ffpath)
      image = image.resize((224,224),Image.LANCZOS)

     
      
      data = np.array(image) / 255.0
      label = label
      datas.append(data)
      labels.append(label)
        
        

  datas = np.array(datas)
  labels = np.array(labels)

  #print("shape of datas: {}\tshape of labels: {}".format(datas.shape,labels.shape))
  return  datas, labels


将训练集和验证集合并为一个训练集 

def get_data(path="/content/drive/MyDrive/Colab Notebooks/Fashion_Dataset"):
  #将path修改为dataset路径
  train_x, train_y = read_data(os.path.join(path,'train'))
  val_x, val_y = read_data(os.path.join(path,'val'))
  test_x, test_y = read_data(os.path.join(path,'test'))
  #合并
  #train_x = np.vstack((train_x,val_x))
  #train_y = np.hstack((train_y,val_y))
  train_x = np.concatenate([train_x,val_x],axis=0)
  train_y = np.concatenate([train_y,val_y],axis=0)
  #训练集打乱
  train_x,train_y=shuffle_datas(train_x,train_y)
  print("shape of datas: {}\tshape of labels: {}".format(train_x.shape,train_y.shape))
  print("shape of datas: {}\tshape of labels: {}".format(test_x.shape,test_y.shape))
  return train_x,train_y,test_x,test_y


# 对数据进行洗牌
def shuffle_datas(x,y):
  index = [i for i in range(len(x))]
  np.random.shuffle(index) 
  x = x[index]
  y = y[index]
  return x,y

#获取数据
train_x,train_y,test_x,test_y = get_data()

K折交叉验证实现(k取5组)

from tensorflow.keras.utils import to_categorical

k=5
num_epochs=25

#算出滑动步长 x_data的shape为(70000,28,28) 划分5组 每个步长为14000
slid_step=int(train_x.shape[0]/k)

#数据类型转换
train_x.astype(dtype='float32')
train_y.astype(dtype="int32")
#historys用来记录5组auc
historys=[]

#五组实验
for i in range(k):
    x_test, y_test = train_x[i * slid_step:(i + 1) * slid_step],train_y[i * slid_step:(i + 1) * slid_step]
    x_train, y_train = train_x[i * slid_step:], train_y[i  * slid_step:]
    #数据形状修改为相同
    y_train = to_categorical(y_train, 2)
    y_test = to_categorical(y_test, 2)
    #读取模型
    model = get_new_model()
    history =model.fit(x_train, y_train,epochs=num_epochs,  
              validation_data=(x_test,y_test), 
              batch_size=64) 
    historys.append(history.history)          

平均准确率

acc_mean=[]
for i in range(5):
   acc_mean=list(range(1,6)),list(historys[i].values())[1]
    
print(acc_mean)
print("平均值acc:",np.sum(list(historys[i].values())[1])/25)

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值