项目说明,本项目是李宏毅老师在飞桨授权课程的作业解析
课程 传送门
该项目AiStudio项目 传送门
数据集 传送门
本项目仅用于参考,提供思路和想法并非标准答案!请谨慎抄袭!
迁移学习
三岁出品,必是精品!
迁移学习:先训练一个模型然后把该模型的参数给类似的项目直接进行训练,效果好极了!
基于这个原理我们开始思考流程
1、数据处理
2、网络定义
3、训练模型
4、固定参数
5、加载模型参数
6、进行迁移学习
本项目的最后结果差的离谱,原因原始模型就不好。
提高分数建议:
1、修改原始网络
2、提高原始模型质量
3、修改训练轮数
4、数据处理更加精准
作业5-迁移学习
项目描述
本作业的任务是迁移学习中的领域对抗性训练(Domain Adversarial Training)。
也就是左下角的那一块。
Domain Adaptation是让模型可以在训练时只需要 A dataset label,不需要 B dataset label 的情况下提高 B dataset 的准确率。 (A dataset & task 接近 B dataset & task)也就是给定真实图片 & 标签以及大量的手绘图片,请设计一种方法使得模型可以预测出手绘图片的标签是什么。
数据集介绍
这次的任务是源数据: 真实照片,目标数据: 手画涂鸦。
我们必须让model看过真实照片以及标签,尝试去预测手画涂鸦的标签为何。
资料位于’data/data58171/real_or_drawing.zip’
- Training : 5000 张真实图片 + label, 32 x 32 RGB
- Testing : 100000 张手绘图片,28 x 28 Gray Scale
- Label: 总共需要预测 10 个 class。
- 资料下载下来是以 0 ~ 9 作为label
特别注意一点: **这次的源数据和目标数据的图片都是平衡的,你们可以使用这个资料做其他事情。 **
项目要求
- 禁止手动标记label或在网上寻找label
- 禁止使用pre-trained model
数据准备
!unzip -oq /home/aistudio/data/data75815/real_or_drawing.zip
import os import paddle import paddle.vision.transforms as T import numpy as np from PIL import Image import paddle.nn.functional as F import random
数据处理
data_path = '/home/aistudio/real_or_drawing/train_data' # 设置初始文件地址 character_folders = os.listdir(data_path) # 查看地址下文件夹 character_folders
['2', '1', '5', '3', '8', '7', '6', '9', '4', '0']
# 新建标签列表 def img_list_text(train='train'): data_path = f'/home/aistudio/real_or_drawing/{train}_data' # 设置初始文件地址 character_folders = os.listdir(data_path) # 查看地址下文件夹 if(os.path.exists(f'./{train}_train_imglist.txt')): # 判断文件是否存在 os.remove(f'./{train}_train_imglist.txt') # 删除文件 if(os.path.exists(f'./{train}_test_imglist.txt')): # 判断文件是否存在 os.remove(f'./{train}_test_imglist.txt') # 删除文件 with open(f'./{train}_train_imglist.txt', 'w')as f_train: with open(f'./{train}_test_imglist.txt', 'w')as f_test: img_list = [] for character_folder in character_folders: # 循环文件夹列表 character_imgs = os.listdir(os.path.join(data_path,character_folder)) # 读取文件夹下面的内容 count = 0 for img in character_imgs: # 循环图片列表 img_list.append(os.path.join(data_path,character_folder,img) + '\t' + character_folder + '\n') # 写入地址及标签 count += 1 print(character_folder,count) # 查看各个目录的图片数量 random.shuffle(img_list) # 打乱列表 count_1 = 0 for img in img_list: # 循环列表 if count_1 < int(len(img_list)*0.8): # 输出前80%为训练集 f_train.write(img) count_1 += 1 else: # 剩下来的为验证集 f_test.write(img) count_1 += 1 print(len(img_list),int(len(img_list)*0.8)) # 查看总数量和训练集数量 img_list_text('train') # 实例化数据 img_list_text('test')
2 500 1 500 5 500 3 500 8 500 7 500 6 500 9 500 4 500 0 500 5000 4000 0 100000 100000 80000
# 继承paddle.io.Dataset对数据集做处理 class FoodDataset(paddle.io.Dataset): """ 数据集类的定义 """ def __init__(self, mode='train'): """ 初始化函数 """ self.data = [] with open(f'{mode}_imglist.txt') as f: # 打开文件 for line in f.readlines(): # 逐行读取 info = line.strip().split('\t') # 以\t进行分隔 if len(info) > 0: self.data.append([info[0].strip(), info[1].strip()]) # 写入文件 def __getitem__(self, index): """ 读取图片,对图片进行归一化处理,返回图片和 标签 """ image_file, label = self.data[index] # 获取数据 img = Image.open(image_file) # 读取图片 img = img.resize((28, 28), Image.ANTIALIAS) # 图片大小样式归一化 img = np.array(img).astype('float32') # 转换成数组类型浮点型32位 img = img.transpose((2, 0, 1)) #读出来的图像是rgb,rgb,rbg..., 转置为 rrr...,ggg...,bbb... img = img/255.0 # 数据缩放到0-1的范围 return img, np.array(label, dtype='int64') def __len__(self): """ 获取样本总数 """ return len(self.data) train_train_img = FoodDataset('train_train') train_test_img = FoodDataset('train_test') # 查看训练和测试数据的大小 print('train大小:', train_train_img.__len__()) print('eval大小:', train_test_img.__len__()) # 查看图片数据、大小及标签 for data, label in train_train_img: print(data[0][1]) print(np.array(data).shape) print(label) break
train大小: 4000 eval大小: 1000 [1. 0.99215686 0.96862745 0.92156863 0.87058824 0.83137256 0.8039216 0.76862746 0.73333335 0.69803923 0.6784314 0.6784314 0.6784314 0.68235296 0.69803923 0.7176471 0.7372549 0.77254903 0.8 0.8156863 0.8156863 0.8039216 0.7921569 0.7647059 0.72156864 0.6745098 0.6117647 0.6313726 ] (3, 28, 28) 6
定义网络
# 继承paddle.nn.Layer类,用于搭建模型 class MLPModel(paddle.nn.Layer): # 继承paddle.nn.Layer类 def __init__(self): super(MLPModel, self).__init__() self.flatten=paddle.nn.Flatten() # 数据拉直 self.hidden=paddle.nn.Linear(in_features=2352,out_features=128) # 线性输入784输出128 self.output=paddle.nn.Linear(in_features=128,out_features=10) # 线性输入128输出10 def forward(self, x): x=self.flatten(x) # 拉直 x=self.hidden(x) # 经过隐藏层(线性层1) x=F.relu(x) # 经过激活层 x=self.output(x) # 经过输出层 return x model=paddle.Model(MLPModel()) # 实例化模型
model.summary((1,3,28,28))
--------------------------------------------------------------------------- Layer (type) Input Shape Output Shape Param # =========================================================================== Flatten-6 [[1, 3, 28, 28]] [1, 2352] 0 Linear-19 [[1, 2352]] [1, 128] 301,184 Linear-20 [[1, 128]] [1, 10] 1,290 =========================================================================== Total params: 302,474 Trainable params: 302,474 Non-trainable params: 0 --------------------------------------------------------------------------- Input size (MB): 0.01 Forward/backward pass size (MB): 0.02 Params size (MB): 1.15 Estimated Total Size (MB): 1.18 --------------------------------------------------------------------------- {'total_params': 302474, 'trainable_params': 302474}
模型训练
# model = paddle.Model(network) # 模型封装 # 配置优化器、损失函数、评估指标 model.prepare(paddle.optimizer.Adam(learning_rate=0.0001, parameters=model.parameters()), paddle.nn.CrossEntropyLoss(), paddle.metric.Accuracy()) # 训练可视化VisualDL工具的回调函数 visualdl = paddle.callbacks.VisualDL(log_dir='visualdl_log') # 启动模型全流程训练 model.fit(train_train_img, # 训练数据集 train_test_img, # 评估数据集 epochs=5, # 训练的总轮次 batch_size=64, # 训练使用的批大小 verbose=1, # 日志展示形式 callbacks=[visualdl]) # 设置可视化
The loss value printed in the log is the current step, and the metric is the average value of previous step. Epoch 1/5 step 63/63 [==============================] - loss: 1.4922 - acc: 0.4325 - 13ms/step Eval begin... The loss value printed in the log is the current batch, and the metric is the average value of previous step. step 16/16 [==============================] - loss: 2.1877 - acc: 0.4000 - 12ms/step Eval samples: 1000 Epoch 2/5 step 63/63 [==============================] - loss: 1.6968 - acc: 0.4325 - 13ms/step Eval begin... The loss value printed in the log is the current batch, and the metric is the average value of previous step. step 16/16 [==============================] - loss: 2.1877 - acc: 0.4000 - 12ms/step Eval samples: 1000 Epoch 3/5 step 63/63 [==============================] - loss: 1.6774 - acc: 0.4325 - 13ms/step Eval begin... The loss value printed in the log is the current batch, and the metric is the average value of previous step. step 16/16 [==============================] - loss: 2.1877 - acc: 0.4000 - 12ms/step Eval samples: 1000 Epoch 4/5 step 63/63 [==============================] - loss: 1.6447 - acc: 0.4325 - 14ms/step Eval begin... The loss value printed in the log is the current batch, and the metric is the average value of previous step. step 16/16 [==============================] - loss: 2.1877 - acc: 0.4000 - 12ms/step Eval samples: 1000 Epoch 5/5 step 63/63 [==============================] - loss: 1.7489 - acc: 0.4325 - 13ms/step Eval begin... The loss value printed in the log is the current batch, and the metric is the average value of previous step. step 16/16 [==============================] - loss: 2.1877 - acc: 0.4000 - 13ms/step Eval samples: 1000
model.save('finetuning/mnist') # 保存模型
迁移学习
# 数据处理 test_train_img = FoodDataset('test_train') test_test_img = FoodDataset('test_test') # 查看训练和测试数据的大小 print('train大小:', train_train_img.__len__()) print('eval大小:', train_test_img.__len__()) # 查看图片数据、大小及标签 for data, label in train_train_img: print(data[0][1]) print(np.array(data).shape) print(label) break
train大小: 80000 eval大小: 20000 [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] (3, 28, 28) 0
# 模型封装,为了后面保存预测模型,这里传入了inputs参数 model_2 = paddle.Model(MLPModel()) # 实例化模型 # 加载之前保存的阶段训练模型 model_2.load('finetuning/mnist') # 模型配置 model_2.prepare(paddle.optimizer.Adam(learning_rate=0.001, parameters=network.parameters()), paddle.nn.CrossEntropyLoss(), paddle.metric.Accuracy()) # 模型全流程训练 model_2.fit(test_train_img, test_test_img, epochs=2, batch_size=64, verbose=1)
The loss value printed in the log is the current step, and the metric is the average value of previous step. Epoch 1/2 step 1250/1250 [==============================] - loss: 2.6177 - acc: 0.0119 - 11ms/step Eval begin... The loss value printed in the log is the current batch, and the metric is the average value of previous step. step 313/313 [==============================] - loss: 2.6651 - acc: 0.0119 - 12ms/step Eval samples: 20000 Epoch 2/2 step 1250/1250 [==============================] - loss: 2.8404 - acc: 0.0119 - 9ms/step Eval begin... The loss value printed in the log is the current batch, and the metric is the average value of previous step. step 313/313 [==============================] - loss: 2.6651 - acc: 0.0119 - 8ms/step Eval samples: 20000
验证结果
result = model.evaluate(test_test_img, verbose=1) # 验证 print(result)
Eval begin... The loss value printed in the log is the current batch, and the metric is the average value of previous step. step 20000/20000 [==============================] - loss: 2.4581 - acc: 0.0119 - 2ms/step Eval samples: 20000 {'loss': [2.4580889], 'acc': 0.0119}
传说中的飞桨社区最菜代码人,让我们一起努力!
记住:三岁出品必是精品 (不要脸系列)