import tensorflow as tf from tensorflow import keras import matplotlib.pyplot as plt %matplotlib inline import numpy as np import pathlib
打印Tensorflow版本 1 print('Tensorflow version:{}'.format(tf.__version__))
打印是否支持GPU加速 1 print(tf.test.is_gpu_available())
图片文件根目录 1 data_dir = './dataset/moc'
1 data_root = pathlib.Path(data_dir)
1 2 data_root WindowsPath('dataset/moc')
获取所有图片路径 1 all_image_paths = list(data_root.glob('*/*'))
1 2 3 4 5 6 7 8 9 10 all_image_paths [WindowsPath('dataset/moc/black_jeans/00000000.jpg'), WindowsPath('dataset/moc/black_jeans/00000001.jpeg'), WindowsPath('dataset/moc/black_jeans/00000002.jpeg'), WindowsPath('dataset/moc/black_jeans/00000003.jpg'), WindowsPath('dataset/moc/black_jeans/00000004.jpg'), WindowsPath('dataset/moc/black_jeans/00000005.jpeg'), WindowsPath('dataset/moc/black_jeans/00000006.jpg'), WindowsPath('dataset/moc/black_jeans/00000007.jpg'), WindowsPath('dataset/moc/black_jeans/00000008.jpeg')]
获取所有图片个数 1 image_count = len(all_image_paths)
所有图片进行乱序 1 2 3 import random all_image_paths = [str(path) for path in all_image_paths]#str变成常见路径方法 random.shuffle(all_image_paths)#路径乱序
1 2 3 4 5 6 7 8 9 10 11 all_image_paths ['dataset\\moc\\blue_jeans\\00000003.jpg', 'dataset\\moc\\blue_dress\\00000065.jpg', 'dataset\\moc\\red_shirt\\00000105.jpg', 'dataset\\moc\\blue_dress\\00000211.jpg', 'dataset\\moc\\blue_dress\\00000226.jpg', 'dataset\\moc\\black_shoes\\00000175.jpg', 'dataset\\moc\\black_shoes\\00000374.jpeg', 'dataset\\moc\\blue_shirt\\00000372.jpg', 'dataset\\moc\\black_shoes\\00000195.jpg', 'dataset\\moc\\red_dress\\00000115.jpg',
获取标签信息 1 label_names = sorted(item.name for item in data_root.glob('*/') if item.is_dir())#item是否为文件夹
data_root.glob( ‘*/*‘ )
1 2 3 4 5 6 7 [WindowsPath('dataset/moc/black_jeans/00000000.jpg'), WindowsPath('dataset/moc/black_jeans/00000001.jpeg'), WindowsPath('dataset/moc/black_jeans/00000002.jpeg'), WindowsPath('dataset/moc/black_jeans/00000003.jpg'), WindowsPath('dataset/moc/black_jeans/00000004.jpg'), WindowsPath('dataset/moc/black_jeans/00000005.jpeg'), WindowsPath('dataset/moc/black_jeans/00000006.jpg')]
data_root.glob(‘*/‘)
1 2 3 4 5 6 7 [WindowsPath('dataset/moc/black_jeans'), WindowsPath('dataset/moc/black_shoes'), WindowsPath('dataset/moc/blue_dress'), WindowsPath('dataset/moc/blue_jeans'), WindowsPath('dataset/moc/blue_shirt'), WindowsPath('dataset/moc/red_dress'), WindowsPath('dataset/moc/red_shirt')]
提取颜色标签 1 color_label_names = set(name.split('_')[0] for name in label_names)#set的方法取唯一,也可以 np.unique
提取类别标签 1 item_label_names = set(name.split('_')[1] for name in label_names)
color->index 1 color_label_to_index = dict((name,index) for index,name in enumerate(color_label_names))
item->index 1 item_label_to_index = dict((name,index) for index,name in enumerate(item_label_names))
获取每张图片对应的标签 1 all_image_labels = [pathlib.Path(path).parent.name for path in all_image_paths]#parent 返回除最底层的上级目录(dataset/moc/black_shoes.name) name名字
每张图片对应标签颜色转下标 1 color_labels = [color_label_to_index[label.split('_')[0]] for label in all_image_labels]
每张图片对应标签物品类别转下标 1 item_labels = [item_label_to_index[label.split('_')[1]] for label in all_image_labels]
验证:绘制图像display.display(display.Image(图片位置路径,width=100,height=100)) 1 2 3 4 5 for n in range(3): image_index = random.choice(range(len(all_image_paths))) display.display(display.Image(all_image_paths[image_index],width=100,height=100)) print(all_image_labels[image_index]) print()
加载和格式化图像 1 2 3 4 5 6 7 8 def load_and_preprocess_image(path): image = tf.io.read_file(path) image = tf.image.decode_jpeg(image,channels=3) image = tf.image.resize(image,[224,224]) image = tf.cast(image,tf.float32) image = image/255.0# 归一化 [0,1] image = 2*image-1#归一化 [-1,1] return image
验证:图片是否正常加载 1 2 3 4 5 6 7 8 9 10 11 import matplotlib.pyplot as plt image_path = all_image_paths[0] label = all_image_labels[0] plt.imshow((load_and_preprocess_image(image_path)+1)/2)#从[-1,1] -> [0,1] plt.grid(False )#表示辅助线,False不显示辅助线 plt.xlabel(label) print()
设置AUTOTUNE 1 AUTOTUNE = tf.data.experimental.AUTOTUNE
设置图片Dataset 1 2 path_ds = tf.data.Dataset.from_tensor_slices(all_image_paths)#将所有图片路径设置为Dataset image_ds = path_ds.map(load_and_preprocess_image,num_parallel_calls=AUTOTUNE)#用map调用(load_and_preprocess_image)函数映射,获取图片数据
设置标签Dataset 1 label_ds =tf.data.Dataset.from_tensor_slices((color_labels,item_labels))
设置图片与标签Dataset 1 image_label_ds = tf.data.Dataset.zip((image_ds,label_ds))
按比例分配train数据集和test数据集 1 2 3 4 5 test_count = int(image_count*0.2) train_count = image_count - test_count train_data = image_label_ds.skip(test_count)#跳过 test_data = image_label_ds.take(test_count)#取
设置BATCH_SIZE
设置train_data 1 2 3 4 5 # train_data = train_data.apply( # tf.data.experimental.shuffle_and_repeat(buffer_size=train_count)) train_data = train_data.shuffle(buffer_size=train_count).repeat(-1)#repeat(-1) = repeat() 一直重复 train_data = train_data.batch(BATCH_SIZE) train_data = train_data.prefetch(buffer_size=AUTOTUNE)#在后台,一部分数据进行训练过程中读取另外一部分数据,能加速训练过程,prefetch(buffer_size) 让计算机自己计算
设置test_data 1 test_data = test_data.batch(BATCH_SIZE)
建立预训练模型 1 2 3 4 mobile_net = tf.keras.applications.MobileNetV2(input_shape=(224,224,3),#本人测试MobileNet比MobileNetV2在这test准确率高,课上MobileNetV2 include_top=False, weights='imagenet' )#没使用预训练权重
将预训练模型设置为不可训练 1 mobile_net.trainable = False
1 inputs = tf.keras.Input(shape=(224,224,3))
1 2 x = mobile_net(inputs)#mobile_net四维,要GlobalAveragePooling2D x = tf.keras.layers.GlobalAveragePooling2D()(x)
设置color的输出层 1 2 3 4 5 x1 = tf.keras.layers.Dense(1024,activation='relu')(x)#第一个输出,输出1024个隐藏单元,对x进行调用 out_color = tf.keras.layers.Dense(len(color_label_names), activation='softmax', name='out_color'#规定name,在编写loss使用字典,写对应的loss )(x1)
设置item的输出层 1 2 3 4 5 x2 = tf.keras.layers.Dense(1024,activation='relu')(x)#第一个输出,输出1024个隐藏单元,对x进行调用 out_item = tf.keras.layers.Dense(len(item_label_names), activation='softmax', name='out_item'#规定name,在编写loss使用字典,写对应的loss )(x2)
模型输入输出整合 1 2 model = tf.keras.Model(inputs=inputs, outputs=[out_color,out_item])
标准训练 模型配置 1 2 3 4 5 model.compile(optimizer=tf.optimizers.Adam(),#optimizer='adam' loss={'out_color':tf.losses.sparse_categorical_crossentropy, 'out_item':tf.losses.sparse_categorical_crossentropy},#使用字典和name达到不同的loss,若输出loss都是同一种可以省略 loss='sparse_categorical_crossentropy', metrics=['acc'] )
设置train_step和test_step 1 2 train_step = train_count//BATCH_SIZE test_step = test_count//BATCH_SIZE
模型训练 1 2 3 4 5 6 7 model.fit( train_data, epochs=10, steps_per_epoch=train_step, validation_data=test_data, validation_steps=test_step )
自定义训练 设置优化器 1 optimizer = tf.keras.optimizers.Adam(learning_rate=0.0001)
定义损失函数 1 2 3 4 def loss_fn(color_r,color_p,item_r,item_p): color_loss = tf.keras.losses.sparse_categorical_crossentropy(color_r,color_p)#颜色损失 item_loss = tf.keras.losses.sparse_categorical_crossentropy(item_r,item_p)#类型损失 return color_loss+item_loss#color_loss*0.8+item_loss*0.2 分配loss权重比
设置loss、color_accuracy、item_accuracy 1 2 3 4 5 6 7 train_loss = tf.keras.metrics.Mean(name='train_loss')#.metrics 表示评价指标模块 train_color_accuracy = tf.keras.metrics.SparseCategoricalAccuracy(name='train_color_accuracy') train_item_accuracy =tf.keras.metrics.SparseCategoricalAccuracy(name='train_item_accuracy') test_loss = tf.keras.metrics.Mean('test_loss')#.metrics 表示评价指标模块 test_color_accuracy = tf.keras.metrics.SparseCategoricalAccuracy(name='test_color_accuracy') test_item_accuracy = tf.keras.metrics.SparseCategoricalAccuracy(name='test_item_accuracy')
设置train_step 1 2 3 4 5 6 7 8 9 10 11 @tf.function # 将训练过程转化为图执行模式 def train_step(images, c_r, i_r): with tf.GradientTape() as tape: c_p, i_p = model(images)#model = tf.keras.Model(inputs=inputs,outputs=[out_color,out_item]) loss = loss_fn(c_r, c_p, i_r, i_p) gradients = tape.gradient(loss, model.trainable_variables)#梯度(计算损失值与可训练参数之间的梯度) 参数:(loss,可训练参数) optimizer.apply_gradients(zip(gradients, model.trainable_variables))#根据计算损失值与可训练参数之间的梯度来优化可训练参数 train_loss(loss) train_color_accuracy(c_r, c_p) train_item_accuracy(i_r, i_p)
设置test_step 1 2 3 4 5 6 7 8 @tf.function # 将训练过程转化为图执行模式 def test_step(images, c_r, i_r): c_p, i_p = model(images)#model = tf.keras.Model(inputs=inputs,outputs=[out_color,out_item]) t_loss = loss_fn(c_r, c_p, i_r, i_p) test_loss(t_loss) test_color_accuracy(c_r, c_p) test_item_accuracy(i_r, i_p)
设置训练 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 EPOCHS = 15 for epoch in range(EPOCHS): # 在下一个epoch开始时,重置评估指标 train_loss.reset_states() train_color_accuracy.reset_states() train_item_accuracy.reset_states() test_loss.reset_states() test_color_accuracy.reset_states() test_item_accuracy.reset_states() for images, (color_r, item_r) in train_data: train_step(images, color_r, item_r) for test_images, (test_color_r, test_item_r) in test_data: test_step(test_images, test_color_r, test_item_r) template = 'Epoch {:.3f}, Loss: {:.3f}, Color_Accuracy: {:.3f}, \ Item_Accuracy: {:.3f}, Test Loss: {:.3f}, \ Test_Color_Accuracy: {:.3f}, Test_Item_Accuracy: {:.3f}' print (template.format(epoch+1, train_loss.result(), train_color_accuracy.result()*100, train_item_accuracy.result()*100, test_loss.result(), test_color_accuracy.result()*100, test_item_accuracy.result()*100 ))
在 TensorFlow 2 中,Eager Execution 默认处于启用状态。界面非常灵活直观(执行一次性运算要简单快速得多),不过,这可能对性能和可部署性造成一定影响。
您可以使用 tf.function 将程序转换为计算图。这是一个转换工具,用于从 Python 代码创建独立于 Python 的数据流图。它可以帮助您创建高效且可移植的模型,并且如果要使用 SavedModel,则必须使用此工具。
本指南介绍 tf.function 的底层工作原理,让您形成概念化理解,从而有效地加以利用。
要点和建议包括:
先在 Eager 模式下调试,然后使用 @tf.function 进行装饰。
不依赖 Python 的副作用,如对象变异或列表追加。
tf.function 最适合处理 TensorFlow 运算;NumPy 和 Python 调用会转换为常量。
模型权重保存 1 model.save_weights('my_multi_output_model.h5')
模型权重读取 1 model.load_weights('my_multi_output_model.h5')
编码问题,例如0->red,blue->1,下次打开时0->不一定为red
模型预测 1 2 3 4 5 my_img_path = 'dataset/blue_dress.jpg'#'dataset//moc//blue_dress//00000001.jpg' my_img = load_and_preprocess_image(my_img_path)#图片加载 my_img = tf.expand_dims(my_img,0)#维度扩展 pred = model.predict(my_img) np.argmax(pred[0]),np.argmax(pred[1])