基于卷积神经网络的美食分类

发布时间 2023-11-05 17:43:11作者: 学弟1

  使用卷积神经网络解决美食图片的分类问题:::数据集在我这里,私聊给!!!!!!!!!

  环境:python3.7 , 飞浆版本2.0 , 操作平台pycharm

  步骤1:美食图片数据集介绍与加载:

  本实践使用的数据集包含5000张格式为jpg的三通道彩色图像,共5种食物类别。对于本实践中的数据包,具体处理与加载的方式与宝石分类类似,如不知,则请看我之前宝石分类的那篇文章

https://www.cnblogs.com/caizhou520/p/17810369.html

  首先定义个方法对数据集的压缩包进行解压缩,解压完成之后可以看到数据集:

1 def unzip_data(src_path,target_path):
2     '''
3     解压原始数据集,将src_path路径下的zip包解压至target_path目录下
4     '''
5     if(not os.path.isdir(target_path + "foods")):     
6         z = zipfile.ZipFile(src_path, 'r')
7         z.extractall(path=target_path)
8         z.close()

  然后,定义get_data_list()方法遍历文件夹和图片,按照一定比例将数据分为训练集和验证集,并生成对应的train.txt和eval.txt文档,然后用json的形式对整个数据集进行一个说明;

 1 def get_data_list(target_path,train_list_path,eval_list_path):
 2     '''
 3     生成数据列表
 4     '''
 5     #存放所有类别的信息
 6     class_detail = []
 7     #获取所有类别保存的文件夹名称
 8     data_list_path=target_path+"foods/"
 9     class_dirs = os.listdir(data_list_path)  
10     #总的图像数量
11     all_class_images = 0
12     #存放类别标签
13     class_label=0
14     #存放类别数目
15     class_dim = 0
16     #存储要写进eval.txt和train.txt中的内容
17     trainer_list=[]
18     eval_list=[]
19     #读取每个类别
20     for class_dir in class_dirs:
21         if class_dir != ".DS_Store":
22             class_dim += 1
23             #每个类别的信息
24             class_detail_list = {}
25             eval_sum = 0
26             trainer_sum = 0
27             #统计每个类别有多少张图片
28             class_sum = 0
29             #获取类别路径 
30             path = data_list_path  + class_dir
31             # 获取所有图片
32             img_paths = os.listdir(path)
33             for img_path in img_paths:                                  # 遍历文件夹下的每个图片
34                 name_path = path + '/' + img_path                       # 每张图片的路径
35                 if class_sum % 10 == 0:                                  # 每10张图片取一个做验证数据
36                     eval_sum += 1                                       # test_sum为测试数据的数目
37                     eval_list.append(name_path + "\t%d" % class_label + "\n")
38                 else:
39                     trainer_sum += 1 
40                     trainer_list.append(name_path + "\t%d" % class_label + "\n")#trainer_sum测试数据的数目
41                 class_sum += 1                                          #每类图片的数目
42                 all_class_images += 1                                   #所有类图片的数目
43              
44             # 说明的json文件的class_detail数据
45             class_detail_list['class_name'] = class_dir             #类别名称
46             class_detail_list['class_label'] = class_label          #类别标签
47             class_detail_list['class_eval_images'] = eval_sum       #该类数据的测试集数目
48             class_detail_list['class_trainer_images'] = trainer_sum #该类数据的训练集数目
49             class_detail.append(class_detail_list)  
50             #初始化标签列表
51             train_parameters['label_dict'][str(class_label)] = class_dir
52             class_label += 1 
53             
54     #初始化分类数
55     train_parameters['class_dim'] = class_dim
56     
57     #乱序  
58     random.shuffle(eval_list)
59     with open(eval_list_path, 'a') as f:
60         for eval_image in eval_list:
61             f.write(eval_image) 
62             
63     random.shuffle(trainer_list)
64     with open(train_list_path, 'a') as f2:
65         for train_image in trainer_list:
66             f2.write(train_image) 
67 
68     # 说明的json文件信息
69     readjson = {}
70     readjson['all_class_name'] = data_list_path                  #文件父目录
71     readjson['all_class_images'] = all_class_images
72     readjson['class_detail'] = class_detail
73     jsons = json.dumps(readjson, sort_keys=True, indent=4, separators=(',', ': '))
74     with open(train_parameters['readme_path'],'w') as f:
75         f.write(jsons)
76     print ('生成数据列表完成!')

     生成train.txt文本和eval.txt文本:

   生成训练数据和测试数据:

 1 class FoodDataset(paddle.io.Dataset):
 2     def __init__(self, data_path, mode='train'):
 3         """
 4         数据读取器
 5         :param data_path: 数据集所在路径
 6         :param mode: train or eval
 7         """
 8         super().__init__()
 9         self.data_path = data_path
10         self.img_paths = []
11         self.labels = []
12 
13         if mode == 'train':
14             with open(os.path.join(self.data_path, "train.txt"), "r", encoding="utf-8") as f:
15                 self.info = f.readlines()
16             for img_info in self.info:
17                 img_path, label = img_info.strip().split('\t')
18                 self.img_paths.append(img_path)
19                 self.labels.append(int(label))
20 
21         else:
22             with open(os.path.join(self.data_path, "eval.txt"), "r", encoding="utf-8") as f:
23                 self.info = f.readlines()
24             for img_info in self.info:
25                 img_path, label = img_info.strip().split('\t')
26                 self.img_paths.append(img_path)
27                 self.labels.append(int(label))
28 
29 
30     def __getitem__(self, index):
31         """
32         获取一组数据
33         :param index: 文件索引号
34         :return:
35         """
36         # 第一步打开图像文件并获取label值
37         img_path = self.img_paths[index]
38         img = Image.open(img_path)
39         if img.mode != 'RGB':
40             img = img.convert('RGB') 
41         img = img.resize((64, 64), Image.BILINEAR)
42         img = np.array(img).astype('float32')
43         img = img.transpose((2, 0, 1)) / 255
44         label = self.labels[index]
45         label = np.array([label], dtype="int64")
46         return img, label
47 
48     def print_sample(self, index: int = 0):
49         print("文件名", self.img_paths[index], "\t标签值", self.labels[index])
50 
51     def __len__(self):
52         return len(self.img_paths)
53 
54 
55 # In[7]:
56 
57 
58 #训练数据加载 
59 train_dataset = FoodDataset(data_path='/home/aistudio/data/',mode='train')
60 train_loader = paddle.io.DataLoader(train_dataset, batch_size=train_parameters['train_batch_size'], shuffle=True)
61 #测试数据加载 
62 eval_dataset = FoodDataset(data_path='/home/aistudio/data/',mode='eval')
63 eval_loader = paddle.io.DataLoader(eval_dataset, batch_size = 8, shuffle=False)

  步骤2:自定义卷积神经网络:

 1 #定义卷积网络
 2 class MyCNN(nn.Layer): 
 3     def __init__(self):
 4         super(MyCNN,self).__init__()
 5         # in_channels, out_channels, kernel_size, stride=1, padding=0
 6         self.conv0 = nn.Conv2D(in_channels = 3,out_channels=64, kernel_size=3,padding=0,stride=1)
 7         self.pool0 = nn.MaxPool2D(kernel_size = 2,stride = 2)
 8         self.conv1 = nn.Conv2D(in_channels = 64,out_channels=128,kernel_size=3,padding=0, stride = 1)
 9         self.pool1 = nn.MaxPool2D(kernel_size = 2, stride = 2)
10         self.conv2 = nn.Conv2D(in_channels = 128,out_channels=128,kernel_size=5,padding=0)
11         self.pool2 = nn.MaxPool2D(kernel_size = 2, stride = 2)
12         self.fc1 = nn.Linear(in_features=128*5*5,out_features=5)
13 
14     def forward(self,input): 
15         x = self.conv0(input)
16         x = self.pool0(x)
17         x = self.conv1(x)
18         x = self.pool1(x)
19         x = self.conv2(x)
20         x = self.pool2(x)
21         x = paddle.reshape(x,shape=[-1,128*5*5])
22         y = self.fc1(x)
23  
24         return y 
25 
26 
27 # In[31]:
28 
29 
30 # 实例化网络
31 model = MyCNN()
32 # 定义输入
33 input_define = paddle.static.InputSpec(shape=[-1, 3 , 64, 64],
34                                    dtype="float32",
35                                    name="img")
36 
37 label_define = paddle.static.InputSpec(shape=[-1, 1],
38                                        dtype="int64",
39                                        name="label")
40 model = paddle.Model(model, inputs=input_define, labels=label_define)
41 params_info = model.summary((1,3,64,64))
42 print(params_info) # 打印模型基础结构和参数信息

  打印出网络结构图,如下图所示,总共做了三次卷积和池化操作,最后经过全连接层,然后再输出5个类别图像的比率,选择概率大的图片:

 

   步骤3:模型的训练:

  定义训练集的准确率图和损失率图:

 1 Batch=0
 2 Batchs=[]
 3 all_train_accs=[]
 4 def draw_train_acc(Batchs, train_accs):
 5     title="training accs"
 6     plt.title(title, fontsize=24)
 7     plt.xlabel("batch", fontsize=14)
 8     plt.ylabel("acc", fontsize=14)
 9     plt.plot(Batchs, train_accs, color='green', label='training accs')
10     plt.legend()
11     plt.grid()
12     plt.show()
13 
14 all_train_loss=[]
15 def draw_train_loss(Batchs, train_loss):
16     title="training loss"
17     plt.title(title, fontsize=24)
18     plt.xlabel("batch", fontsize=14)
19     plt.ylabel("loss", fontsize=14)
20     plt.plot(Batchs, train_loss, color='red', label='training loss')
21     plt.legend()
22     plt.grid()
23     plt.show()

  对模型进行训练,把训练好的模型的准确率和损失率通过定义的matplotlib画出来:

 1 model=MyCNN() # 模型实例化
 2 model.train() # 训练模式
 3 cross_entropy = paddle.nn.CrossEntropyLoss()
 4 opt=paddle.optimizer.SGD(learning_rate=0.001, parameters=model.parameters())
 5 
 6 epochs_num=train_parameters['num_epochs'] #迭代次数
 7 for pass_num in range(train_parameters['num_epochs']):
 8     for batch_id,data in enumerate(train_loader()):
 9         image = data[0]
10         label = data[1]
11         predict=model(image) #数据传入model
12         # print(predict)
13         # print(np.argmax(predict,axis=1))
14         loss=cross_entropy(predict,label)
15         acc=paddle.metric.accuracy(predict,label.reshape([-1,1]))#计算精度
16         # acc = np.mean(label==np.argmax(predict,axis=1))
17         
18         if batch_id!=0 and batch_id%10==0:
19             Batch = Batch+10
20             Batchs.append(Batch)
21             all_train_loss.append(loss.numpy()[0])
22             all_train_accs.append(acc.numpy()[0]) 
23             print("epoch:{},step:{},train_loss:{},train_acc:{}".format(pass_num,batch_id,loss.numpy()[0],acc.numpy()[0]))        
24         loss.backward()       
25         opt.step()
26         opt.clear_grad()   #opt.clear_grad()来重置梯度
27 paddle.save(model.state_dict(),'MyCNN')#保存模型
28 draw_train_acc(Batchs,all_train_accs)
29 draw_train_loss(Batchs,all_train_loss)

   

  步骤4:使用验证集数据对模型的好坏进行评估:

 1 #模型评估
 2 para_state_dict = paddle.load("MyCNN") 
 3 model = MyCNN()
 4 model.set_state_dict(para_state_dict) #加载模型参数
 5 model.eval() #验证模式
 6 
 7 accs = []
 8 
 9 for batch_id,data in enumerate(eval_loader()):#测试集
10     image=data[0]
11     label=data[1]     
12     predict=model(image)       
13     acc=paddle.metric.accuracy(predict,label)
14     accs.append(acc.numpy()[0])
15     avg_acc = np.mean(accs)
16 print("当前模型在验证集上的准确率为:",avg_acc)

  由图可知,其模型在验证集的准确率较低。可能是由于训练迭代的次数比较少,建议改进模型进行迭代;

   步骤5:预测一个新的图像是否和真实的类别保持一致

  

 1 '''
 2 模型预测
 3 '''
 4 
 5 para_state_dict = paddle.load("MyCNN")
 6 model = MyCNN()
 7 model.set_state_dict(para_state_dict) #加载模型参数
 8 model.eval() #验证模式
 9 
10 #展示预测图片
11 infer_path='data/foods/baklava/1936599.jpg'
12 img = Image.open(infer_path)
13 plt.imshow(img)          #根据数组绘制图像
14 plt.show()               #显示图像
15 #对预测图片进行预处理
16 infer_imgs = []
17 infer_imgs.append(load_image(infer_path))
18 infer_imgs = np.array(infer_imgs)
19 label_dic = train_parameters['label_dict']
20 for i in range(len(infer_imgs)):
21     data = infer_imgs[i]
22     dy_x_data = np.array(data).astype('float32')
23     dy_x_data=dy_x_data[np.newaxis,:, : ,:]
24     img = paddle.to_tensor (dy_x_data)
25     out = model(img)
26     lab = np.argmax(out.numpy())  #argmax():返回最大数的索引
27     print("第{}个样本,被预测为:{},真实标签为:{}".format(i+1,label_dic[str(lab)],infer_path.split('/')[-2]) )     
28 print("结束")

  本实验完整代码如下所示:

  1 #!/usr/bin/env python
  2 # coding: utf-8
  3 
  4 # 
  5 
  6 # ## 任务描述:
  7 # 
  8 # ### 如何根据据图像的视觉内容为图像赋予一个语义类别是**图像分类**的目标,也是图像检索、图像内容分析和目标识别等问题的基础。
  9 # 
 10 # ### 本实践旨在通过一个美食分类的案列,让大家理解和掌握如何使用飞桨动态图搭建一个**卷积神经网络**。
 11 # 
 12 # ### 特别提示:本实践所用数据集均来自互联网,请勿用于商务用途。
 13 
 14 # In[32]:
 15 
 16 
 17 import os
 18 import zipfile
 19 import random
 20 import json
 21 import paddle
 22 import sys
 23 import numpy as np
 24 from PIL import Image
 25 from PIL import ImageEnhance
 26 import paddle
 27 from paddle import fluid
 28 import matplotlib.pyplot as plt 
 29 import paddle.vision.transforms as T  
 30 import paddle.nn as nn
 31 import paddle.nn.functional as F
 32 
 33 
 34 # In[33]:
 35 
 36 
 37 '''
 38 参数配置
 39 '''
 40 train_parameters = {
 41     "input_size": [3, 64, 64],                                #输入图片的shape
 42     "class_dim": 5,                                          #分类数
 43     "src_path":"data/data42610/foods.zip",                    #原始数据集路径
 44     "target_path":"/home/aistudio/data/",                     #要解压的路径
 45     "train_list_path": "/home/aistudio/data/train.txt",       #train.txt路径
 46     "eval_list_path": "/home/aistudio/data/eval.txt",         #eval.txt路径
 47     "readme_path": "/home/aistudio/data/readme.json",         #readme.json路径
 48     "label_dict":{},                                          #标签字典
 49     "num_epochs": 2,                                          #训练轮数
 50     "train_batch_size": 64,                                   #训练时每个批次的大小
 51     "learning_strategy": {                                    #优化函数相关的配置
 52         "lr": 0.01                                          #超参数学习率
 53     } 
 54 }
 55 
 56 
 57 # In[34]:
 58 
 59 
 60 print(paddle.__version__)
 61 
 62 
 63 # # **一、数据准备**
 64 # 
 65 # ### (1)解压原始数据集
 66 # 
 67 # ### (2)按照比例划分训练集与验证集
 68 # 
 69 # ### (3)乱序,生成数据列表
 70 # 
 71 # ### (4)构造训练数据集提供器和验证数据集提供器
 72 
 73 # In[35]:
 74 
 75 
 76 
 77 def unzip_data(src_path,target_path):
 78     '''
 79     解压原始数据集,将src_path路径下的zip包解压至target_path目录下
 80     '''
 81     if(not os.path.isdir(target_path + "foods")):     
 82         z = zipfile.ZipFile(src_path, 'r')
 83         z.extractall(path=target_path)
 84         z.close()
 85 
 86 def get_data_list(target_path,train_list_path,eval_list_path):
 87     '''
 88     生成数据列表
 89     '''
 90     #存放所有类别的信息
 91     class_detail = []
 92     #获取所有类别保存的文件夹名称
 93     data_list_path=target_path+"foods/"
 94     class_dirs = os.listdir(data_list_path)  
 95     #总的图像数量
 96     all_class_images = 0
 97     #存放类别标签
 98     class_label=0
 99     #存放类别数目
100     class_dim = 0
101     #存储要写进eval.txt和train.txt中的内容
102     trainer_list=[]
103     eval_list=[]
104     #读取每个类别
105     for class_dir in class_dirs:
106         if class_dir != ".DS_Store":
107             class_dim += 1
108             #每个类别的信息
109             class_detail_list = {}
110             eval_sum = 0
111             trainer_sum = 0
112             #统计每个类别有多少张图片
113             class_sum = 0
114             #获取类别路径 
115             path = data_list_path  + class_dir
116             # 获取所有图片
117             img_paths = os.listdir(path)
118             for img_path in img_paths:                                  # 遍历文件夹下的每个图片
119                 name_path = path + '/' + img_path                       # 每张图片的路径
120                 if class_sum % 10 == 0:                                  # 每10张图片取一个做验证数据
121                     eval_sum += 1                                       # test_sum为测试数据的数目
122                     eval_list.append(name_path + "\t%d" % class_label + "\n")
123                 else:
124                     trainer_sum += 1 
125                     trainer_list.append(name_path + "\t%d" % class_label + "\n")#trainer_sum测试数据的数目
126                 class_sum += 1                                          #每类图片的数目
127                 all_class_images += 1                                   #所有类图片的数目
128              
129             # 说明的json文件的class_detail数据
130             class_detail_list['class_name'] = class_dir             #类别名称
131             class_detail_list['class_label'] = class_label          #类别标签
132             class_detail_list['class_eval_images'] = eval_sum       #该类数据的测试集数目
133             class_detail_list['class_trainer_images'] = trainer_sum #该类数据的训练集数目
134             class_detail.append(class_detail_list)  
135             #初始化标签列表
136             train_parameters['label_dict'][str(class_label)] = class_dir
137             class_label += 1 
138             
139     #初始化分类数
140     train_parameters['class_dim'] = class_dim
141     
142     #乱序  
143     random.shuffle(eval_list)
144     with open(eval_list_path, 'a') as f:
145         for eval_image in eval_list:
146             f.write(eval_image) 
147             
148     random.shuffle(trainer_list)
149     with open(train_list_path, 'a') as f2:
150         for train_image in trainer_list:
151             f2.write(train_image) 
152 
153     # 说明的json文件信息
154     readjson = {}
155     readjson['all_class_name'] = data_list_path                  #文件父目录
156     readjson['all_class_images'] = all_class_images
157     readjson['class_detail'] = class_detail
158     jsons = json.dumps(readjson, sort_keys=True, indent=4, separators=(',', ': '))
159     with open(train_parameters['readme_path'],'w') as f:
160         f.write(jsons)
161     print ('生成数据列表完成!')
162 
163 
164 # In[5]:
165 
166 
167 '''
168 参数初始化
169 '''
170 src_path=train_parameters['src_path']
171 target_path=train_parameters['target_path']
172 train_list_path=train_parameters['train_list_path']
173 eval_list_path=train_parameters['eval_list_path']
174 batch_size=train_parameters['train_batch_size']
175 
176 '''
177 解压原始数据到指定路径
178 '''
179 unzip_data(src_path,target_path)
180 
181 '''
182 划分训练集与验证集,乱序,生成数据列表
183 '''
184 #每次生成数据列表前,首先清空train.txt和eval.txt
185 with open(train_list_path, 'w') as f: 
186     f.seek(0)
187     f.truncate() 
188 with open(eval_list_path, 'w') as f: 
189     f.seek(0)
190     f.truncate() 
191     
192 #生成数据列表   
193 get_data_list(target_path,train_list_path,eval_list_path)
194 
195 
196 # In[6]:
197 
198 
199 
200 class FoodDataset(paddle.io.Dataset):
201     def __init__(self, data_path, mode='train'):
202         """
203         数据读取器
204         :param data_path: 数据集所在路径
205         :param mode: train or eval
206         """
207         super().__init__()
208         self.data_path = data_path
209         self.img_paths = []
210         self.labels = []
211 
212         if mode == 'train':
213             with open(os.path.join(self.data_path, "train.txt"), "r", encoding="utf-8") as f:
214                 self.info = f.readlines()
215             for img_info in self.info:
216                 img_path, label = img_info.strip().split('\t')
217                 self.img_paths.append(img_path)
218                 self.labels.append(int(label))
219 
220         else:
221             with open(os.path.join(self.data_path, "eval.txt"), "r", encoding="utf-8") as f:
222                 self.info = f.readlines()
223             for img_info in self.info:
224                 img_path, label = img_info.strip().split('\t')
225                 self.img_paths.append(img_path)
226                 self.labels.append(int(label))
227 
228 
229     def __getitem__(self, index):
230         """
231         获取一组数据
232         :param index: 文件索引号
233         :return:
234         """
235         # 第一步打开图像文件并获取label值
236         img_path = self.img_paths[index]
237         img = Image.open(img_path)
238         if img.mode != 'RGB':
239             img = img.convert('RGB') 
240         img = img.resize((64, 64), Image.BILINEAR)
241         img = np.array(img).astype('float32')
242         img = img.transpose((2, 0, 1)) / 255
243         label = self.labels[index]
244         label = np.array([label], dtype="int64")
245         return img, label
246 
247     def print_sample(self, index: int = 0):
248         print("文件名", self.img_paths[index], "\t标签值", self.labels[index])
249 
250     def __len__(self):
251         return len(self.img_paths)
252 
253 
254 # In[7]:
255 
256 
257 #训练数据加载 
258 train_dataset = FoodDataset(data_path='/home/aistudio/data/',mode='train')
259 train_loader = paddle.io.DataLoader(train_dataset, batch_size=train_parameters['train_batch_size'], shuffle=True)
260 #测试数据加载 
261 eval_dataset = FoodDataset(data_path='/home/aistudio/data/',mode='eval')
262 eval_loader = paddle.io.DataLoader(eval_dataset, batch_size = 8, shuffle=False)
263 
264 
265 # In[8]:
266 
267 
268 print(train_dataset.__len__())
269 print(eval_dataset.__len__())
270 
271 
272 # # **二、模型配置**
273 # 
274 # 
275 
276 # In[30]:
277 
278 
279 #定义卷积网络
280 class MyCNN(nn.Layer): 
281     def __init__(self):
282         super(MyCNN,self).__init__()
283         # in_channels, out_channels, kernel_size, stride=1, padding=0
284         self.conv0 = nn.Conv2D(in_channels = 3,out_channels=64, kernel_size=3,padding=0,stride=1)
285         self.pool0 = nn.MaxPool2D(kernel_size = 2,stride = 2)
286         self.conv1 = nn.Conv2D(in_channels = 64,out_channels=128,kernel_size=3,padding=0, stride = 1)
287         self.pool1 = nn.MaxPool2D(kernel_size = 2, stride = 2)
288         self.conv2 = nn.Conv2D(in_channels = 128,out_channels=128,kernel_size=5,padding=0)
289         self.pool2 = nn.MaxPool2D(kernel_size = 2, stride = 2)
290         self.fc1 = nn.Linear(in_features=128*5*5,out_features=5)
291 
292     def forward(self,input): 
293         x = self.conv0(input)
294         x = self.pool0(x)
295         x = self.conv1(x)
296         x = self.pool1(x)
297         x = self.conv2(x)
298         x = self.pool2(x)
299         x = paddle.reshape(x,shape=[-1,128*5*5])
300         y = self.fc1(x)
301  
302         return y 
303 
304 
305 # In[31]:
306 
307 
308 # 实例化网络
309 model = MyCNN()
310 # 定义输入
311 input_define = paddle.static.InputSpec(shape=[-1, 3 , 64, 64],
312                                    dtype="float32",
313                                    name="img")
314 
315 label_define = paddle.static.InputSpec(shape=[-1, 1],
316                                        dtype="int64",
317                                        name="label")
318 model = paddle.Model(model, inputs=input_define, labels=label_define)
319 params_info = model.summary((1,3,64,64))
320 print(params_info) # 打印模型基础结构和参数信息
321 
322 
323 # # **三、模型训练 && 四、模型评估**
324 
325 # In[24]:
326 
327 
328 Batch=0
329 Batchs=[]
330 all_train_accs=[]
331 def draw_train_acc(Batchs, train_accs):
332     title="training accs"
333     plt.title(title, fontsize=24)
334     plt.xlabel("batch", fontsize=14)
335     plt.ylabel("acc", fontsize=14)
336     plt.plot(Batchs, train_accs, color='green', label='training accs')
337     plt.legend()
338     plt.grid()
339     plt.show()
340 
341 all_train_loss=[]
342 def draw_train_loss(Batchs, train_loss):
343     title="training loss"
344     plt.title(title, fontsize=24)
345     plt.xlabel("batch", fontsize=14)
346     plt.ylabel("loss", fontsize=14)
347     plt.plot(Batchs, train_loss, color='red', label='training loss')
348     plt.legend()
349     plt.grid()
350     plt.show()
351 
352 
353 # In[25]:
354 
355 
356 model=MyCNN() # 模型实例化
357 model.train() # 训练模式
358 cross_entropy = paddle.nn.CrossEntropyLoss()
359 opt=paddle.optimizer.SGD(learning_rate=0.001, parameters=model.parameters())
360 
361 epochs_num=train_parameters['num_epochs'] #迭代次数
362 for pass_num in range(train_parameters['num_epochs']):
363     for batch_id,data in enumerate(train_loader()):
364         image = data[0]
365         label = data[1]
366         predict=model(image) #数据传入model
367         # print(predict)
368         # print(np.argmax(predict,axis=1))
369         loss=cross_entropy(predict,label)
370         acc=paddle.metric.accuracy(predict,label.reshape([-1,1]))#计算精度
371         # acc = np.mean(label==np.argmax(predict,axis=1))
372         
373         if batch_id!=0 and batch_id%10==0:
374             Batch = Batch+10
375             Batchs.append(Batch)
376             all_train_loss.append(loss.numpy()[0])
377             all_train_accs.append(acc.numpy()[0]) 
378             print("epoch:{},step:{},train_loss:{},train_acc:{}".format(pass_num,batch_id,loss.numpy()[0],acc.numpy()[0]))        
379         loss.backward()       
380         opt.step()
381         opt.clear_grad()   #opt.clear_grad()来重置梯度
382 paddle.save(model.state_dict(),'MyCNN')#保存模型
383 draw_train_acc(Batchs,all_train_accs)
384 draw_train_loss(Batchs,all_train_loss)
385 
386 
387 # # **五、模型评估**
388 
389 # In[12]:
390 
391 
392 #模型评估
393 para_state_dict = paddle.load("MyCNN") 
394 model = MyCNN()
395 model.set_state_dict(para_state_dict) #加载模型参数
396 model.eval() #验证模式
397 
398 accs = []
399 
400 for batch_id,data in enumerate(eval_loader()):#测试集
401     image=data[0]
402     label=data[1]     
403     predict=model(image)       
404     acc=paddle.metric.accuracy(predict,label)
405     accs.append(acc.numpy()[0])
406     avg_acc = np.mean(accs)
407 print("当前模型在验证集上的准确率为:",avg_acc)
408 
409 
410 # In[13]:
411 
412 
413 import os
414 import zipfile
415 
416 def unzip_infer_data(src_path,target_path):
417     '''
418     解压预测数据集
419     '''
420     if(not os.path.isdir(target_path)):     
421         z = zipfile.ZipFile(src_path, 'r')
422         z.extractall(path=target_path)
423         z.close()
424 
425 
426 def load_image(img_path):
427     '''
428     预测图片预处理
429     '''
430     img = Image.open(img_path) 
431     if img.mode != 'RGB': 
432         img = img.convert('RGB') 
433     img = img.resize((64, 64), Image.BILINEAR)
434     img = np.array(img).astype('float32') 
435     img = img.transpose((2, 0, 1))  # HWC to CHW 
436     img = img/255                # 像素值归一化 
437     return img
438 
439 
440 infer_src_path = '/home/aistudio/data/data42610/foods.zip'
441 infer_dst_path = '/home/aistudio/data/foods_test'
442 unzip_infer_data(infer_src_path,infer_dst_path)
443 
444 '''
445 模型预测
446 '''
447 
448 para_state_dict = paddle.load("MyCNN")
449 model = MyCNN()
450 model.set_state_dict(para_state_dict) #加载模型参数
451 model.eval() #验证模式
452 
453 #展示预测图片
454 infer_path='data/foods/baklava/1936599.jpg'
455 img = Image.open(infer_path)
456 plt.imshow(img)          #根据数组绘制图像
457 plt.show()               #显示图像
458 #对预测图片进行预处理
459 infer_imgs = []
460 infer_imgs.append(load_image(infer_path))
461 infer_imgs = np.array(infer_imgs)
462 label_dic = train_parameters['label_dict']
463 for i in range(len(infer_imgs)):
464     data = infer_imgs[i]
465     dy_x_data = np.array(data).astype('float32')
466     dy_x_data=dy_x_data[np.newaxis,:, : ,:]
467     img = paddle.to_tensor (dy_x_data)
468     out = model(img)
469     lab = np.argmax(out.numpy())  #argmax():返回最大数的索引
470     print("第{}个样本,被预测为:{},真实标签为:{}".format(i+1,label_dic[str(lab)],infer_path.split('/')[-2]) )     
471 print("结束")