Mrli
别装作很努力,
因为结局不会陪你演戏。
Contacts:
QQ博客园

浙大2020春夏-人工智能习题2——垃圾分类

2020/12/19 ZJU ML
Word count: 6,612 | Reading time: 30min

homework for ZJU: https://mo.zju.edu.cn/homework/zju_ai_2020_ss

1. 实验介绍

1.1 实验背景

自今年 7 月 1 日起,上海市将正式实施 《上海市生活垃圾管理条例》。
垃圾分类,看似是微不足道的“小事”,实则关系到13亿多人生活环境的改善,理应大力提倡。
垃圾识别分类数据集中包括玻璃 (glass) 、硬纸板 (cardboard) 、金属 (metal) 、纸 (paper) 、塑料 (plastic) 、一般垃圾 (trash) ,共6个类别。
生活垃圾由于种类繁多,具体分类缺乏统一标准,大多人在实际操作时会“选择困难”,基于深度学习技术建立准确的分类模型,利用技术手段改善人居环境。

1.2 实验要求

a)建立深度神经网络模型,并尽可能将其调到最佳状态。
b)绘制深度神经网络模型图、绘制并分析学习曲线。
c)用准确率等指标对模型进行评估。

1.3 实验环境

可以使用基于 Python 的 OpenCV 库进行图像相关处理,使用 Numpy 库进行相关数值运算,使用 Keras 等框架建立深度学习模型等。

2.实验内容

2.1 介绍数据集

该数据集包含了 2307 个生活垃圾图片。数据集的创建者将垃圾分为了 6 个类别,分别是:

序号 中文名 英文名 数据集大小
1 玻璃 glass 457
2 paper 540
3 硬纸板 cardboard 370
4 塑料 plastic 445
5 金属 metal 380
6 一般垃圾 trash 115
  • 物品都是放在白板上在日光/室内光源下拍摄的,压缩后的尺寸为 512 * 384

2.2 图片预处理

图片生成器 ImageDataGenerator: keras.preprocessing.image 模块中的图片生成器,主要用以生成一个 batch 的图像数据,支持实时数据提升。训练时该函数会无限生成数据,直到达到规定的 epoch 次数为止。同时也可以在 batch 中对数据进行增强,扩充数据集大小,增强模型的泛化能力,比如进行旋转,变形,归一化等等。

图片生成器的主要方法:

  • fit(x, augment=False, rounds=1):计算依赖于数据的变换所需要的统计信息(均值方差等)。

  • flow(self, X, y, batch_size=32, shuffle=True, seed=None, save_to_dir=None, save_prefix=’’, save_format=‘png’):接收 Numpy 数组和标签为参数,生成经过数据提升或标准化后的 batch 数据,并在一个无限循环中不断的返回 batch 数据。

  • flow_from_directory(directory): 以文件夹路径为参数,会从路径推测 label,生成经过数据提升/归一化后的数据,在一个无限循环中无限产生 batch 数据。

根据上面的介绍和我们数据集的特性,我们主要运用 ImageDataGenerator()flow_from_directory() 方法。我们将数据处理过程封装成为一个函数:

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# 导入图片生成器
from keras.preprocessing.image import ImageDataGenerator


def processing_data(data_path, height, width, batch_size=32, validation_split=0.1):
"""
数据处理
:param data_path: 带有子目录的数据集路径
:param height: 图像形状的行数
:param width: 图像形状的列数
:param batch_size: batch 数据的大小,整数,默认32。
:param validation_split: 在 0 和 1 之间浮动。用作测试集的训练数据的比例,默认0.1。
:return: train_generator, validation_generator: 处理后的训练集数据、验证集数据
"""

train_data = ImageDataGenerator(
# 对图片的每个像素值均乘上这个放缩因子,把像素值放缩到0和1之间有利于模型的收敛
rescale=1. / 255,
# 浮点数,剪切强度(逆时针方向的剪切变换角度)
shear_range=0.1,
# 随机缩放的幅度,若为浮点数,则相当于[lower,upper] = [1 - zoom_range, 1+zoom_range]
zoom_range=0.1,
# 浮点数,图片宽度的某个比例,数据提升时图片水平偏移的幅度
width_shift_range=0.1,
# 浮点数,图片高度的某个比例,数据提升时图片竖直偏移的幅度
height_shift_range=0.1,
# 布尔值,进行随机水平翻转
horizontal_flip=True,
# 布尔值,进行随机竖直翻转
vertical_flip=True,
# 在 0 和 1 之间浮动。用作验证集的训练数据的比例
validation_split=validation_split
)

# 接下来生成测试集,可以参考训练集的写法
validation_data = ImageDataGenerator(
rescale=1. / 255,
validation_split=validation_split)

train_generator = train_data.flow_from_directory(
# 提供的路径下面需要有子目录
data_path,
# 整数元组 (height, width),默认:(256, 256)。 所有的图像将被调整到的尺寸。
target_size=(height, width),
# 一批数据的大小
batch_size=batch_size,
# "categorical", "binary", "sparse", "input" 或 None 之一。
# 默认:"categorical",返回one-hot 编码标签。
class_mode='categorical',
# 数据子集 ("training" 或 "validation")
subset='training',
seed=0)
validation_generator = validation_data.flow_from_directory(
data_path,
target_size=(height, width),
batch_size=batch_size,
class_mode='categorical',
subset='validation',
seed=0)

return train_generator, validation_generator

# -------------使用---------------------

# 数据路径
data_path = "./datasets/la1ji1fe1nle4ishu4ju4ji22-momodel/dataset-resized"

# 图像数据的行数和列数
height, width = 384, 512

# 获取训练数据和验证数据集
train_generator, validation_generator = processing_data(data_path, height, width)

# 通过属性class_indices可获得文件夹名与类的序号的对应字典。 (类别的顺序将按照字母表顺序映射到标签值)。
labels = train_generator.class_indices
print(labels)

# 转换为类的序号与文件夹名对应的字典
labels = dict((v, k) for k, v in labels.items())
print(labels)
"""
Found 2078 images belonging to 6 classes.
Found 229 images belonging to 6 classes.
{'trash': 5, 'metal': 2, 'plastic': 4, 'glass': 1, 'cardboard': 0, 'paper': 3}
{0: 'cardboard', 1: 'glass', 2: 'metal', 3: 'paper', 4: 'plastic', 5: 'trash'}
"""

2.3 采用 Keras 建立一个简单的深度神经网络模型

通过 Keras 构建深度学习模型的步骤如下:

1. 定义模型——创建一个模型并添加配置层

Keras 的核心数据结构是 model,一种组织网络层的方式。最简单的模型是 Sequential 顺序模型,它由多个网络层线性堆叠。

  1. 方式一: 使用 .add() 方法将各层添加到模型中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 方式一: 使用 .add() 方法将各层添加到模型中
# 导入相关包
from keras.models import Sequential
from keras.layers import Dense, Activation

# 选择模型,选择序贯模型(Sequential())
model = Sequential()
# 构建网络层
# 添加全连接层,输入784维,输出空间维度32
model.add(Dense(32, input_shape=(784,)))
# 添加激活层,激活函数是 relu
model.add(Activation('relu'))
# 打印模型概况
model.summary()
  1. 方式二:网络层实例的列表构建序贯模型

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    # 方式二:网络层实例的列表构建序贯模型
    # 导入相关的包
    from keras.models import Sequential
    from keras.layers import Dense, Activation

    # 选择模型,选择序贯模型(Sequential())
    # 通过将网络层实例的列表传递给 Sequential 的构造器,来创建一个 Sequential 模型
    model = Sequential([
    Dense(32, input_shape=(784,)),
    Activation('relu')
    ])
    # 打印模型概况
    model.summary()
  2. 方式三:函数式模型

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    # 方式三:函数式模型
    # 导入相关的包
    from keras.layers import Input, Dense,Activation
    from keras.models import Model

    # 输入层,返回一个张量 tensor
    inputs = Input(shape=(784,))
    # 全连接层,返回一个张量
    output_1 = Dense(32)(inputs)
    # 激活函数层
    predictions= Activation(activation='relu')(output_1)
    # 创建一个模型,包含输入层、全连接层和激活层
    model = Model(inputs=inputs, outputs=predictions)
    # 打印模型概况
    model.summary()

2. 编译模型——指定损失函数和优化器,并调用模型的 compile() 函数,完成模型编译。

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# 导入相关包
from keras.layers import Input, Dense, Flatten, Dropout, Activation
from keras.layers.normalization import BatchNormalization
from keras.models import Model
from keras.callbacks import TensorBoard
import time


def dnn_model(input_shape, train_generator, validation_generator, model_save_path='results/dnn.h5',
log_dir="results/logs/"):
"""
该函数实现 Keras 创建深度学习模型的过程. ▲.定义模型+编译模型
:param input_shape: 模型数据形状大小,比如:input_shape=(384, 512, 3)
:param train_generator: 训练集
:param validation_generator: 验证集
:param model_save_path: 保存模型的路径
:param log_dir: 保存模型日志路径
:return: 返回已经训练好的模型
"""
# Input 用于实例化 Keras 张量。
# shape: 一个尺寸元组(整数),不包含批量大小。 例如,shape=(32,) 表明期望的输入是按批次的 32 维向量。
inputs = Input(shape=input_shape)

# 将输入展平
dnn = Flatten()(inputs)

# Dense 全连接层 实现以下操作:output = activation(dot(input, kernel) + bias)
# 其中 activation 是按逐个元素计算的激活函数,kernel 是由网络层创建的权值矩阵,
# 以及 bias 是其创建的偏置向量 (只在 use_bias 为 True 时才有用)。
dnn = Dense(6)(dnn)
# 批量标准化层: 在每一个批次的数据中标准化前一层的激活项, 即应用一个维持激活项平均值接近 0,标准差接近 1 的转换。
# axis: 整数,需要标准化的轴 (通常是特征轴)。默认值是 -1
dnn = BatchNormalization(axis=-1)(dnn)
# 将激活函数,输出尺寸与输入尺寸一样,激活函数可以是'softmax'、'sigmoid'等
dnn = Activation('sigmoid')(dnn)
# Dropout 包括在训练中每次更新时,将输入单元的按比率随机设置为 0, 这有助于防止过拟合。
# rate: 在 0 和 1 之间浮动。需要丢弃的输入比例。
dnn = Dropout(0.25)(dnn)

dnn = Dense(12)(dnn)
dnn = BatchNormalization(axis=-1)(dnn)
dnn = Activation('relu')(dnn)
dnn = Dropout(0.5)(dnn)

dnn = Dense(6)(dnn)
dnn = BatchNormalization(axis=-1)(dnn)
dnn = Activation('softmax')(dnn)

outputs = dnn

# 生成一个函数型模型
model = Model(inputs=inputs, outputs=outputs)

# 编译模型, 采用 compile 函数: https://keras.io/models/model/#compile
model.compile(
# 是优化器, 主要有Adam、sgd、rmsprop等方式。
optimizer='Adam',
# 损失函数,多分类采用 categorical_crossentropy
loss='categorical_crossentropy',
# 是除了损失函数值之外的特定指标, 分类问题一般都是准确率
metrics=['accuracy'])

# 可视化,TensorBoard 是由 Tensorflow 提供的一个可视化工具。
tensorboard = TensorBoard(log_dir)

# 训练模型, fit_generator函数:https://keras.io/models/model/#fit_generator
# 利用Python的生成器,逐个生成数据的batch并进行训练。
# callbacks: 实例列表。在训练时调用的一系列回调。详见 https://keras.io/callbacks/。
d = model.fit_generator(
# 一个生成器或 Sequence 对象的实例
generator=train_generator,
# epochs: 整数,数据的迭代总轮数。
epochs=5,
# 一个epoch包含的步数,通常应该等于你的数据集的样本数量除以批量大小。
steps_per_epoch=2076 // 32,
# 验证集
validation_data=validation_generator,
# 在验证集上,一个epoch包含的步数,通常应该等于你的数据集的样本数量除以批量大小。
validation_steps=231 // 32,
callbacks=[tensorboard])
# 模型保存
model.save(model_save_path)

return d, model

3. 训练模型——通过调用模型的 fit() 函数来训练模型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 开始时间
start = time.time()
# 数据预处理
data_path = "./datasets/la1ji1fe1nle4ishu4ju4ji22-momodel/dataset-resized"
# 图像数据的行数和列数
height, width = 384, 512
# 获取训练数据和验证数据
train_generator, validation_generator = processing_data(data_path, height, width)
# 定义模型输入大小
input_shape=(384, 512, 3)
# 训练模型,获取训练过程和训练后的模型
res,model = dnn_model(input_shape, train_generator, validation_generator)
# 打印模型概况和模型训练总数长
model.summary()
print("模型训练总时长:",time.time()-start)
  1. 查看模型训练效果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def plot_training_history(res):
"""
绘制模型的训练结果
:param res: 模型的训练结果
:return:
"""
# 绘制模型训练过程的损失和平均损失
# 绘制模型训练过程的损失值曲线,标签是 loss
plt.plot(res.history['loss'], label='loss')
# 绘制模型训练过程中的平均损失曲线,标签是 val_loss
plt.plot(res.history['val_loss'], label='val_loss')
# 绘制图例,展示出每个数据对应的图像名称和图例的放置位置
plt.legend(loc='upper right')
# 展示图片
plt.show()
# 绘制模型训练过程中的的准确率和平均准确率
# 绘制模型训练过程中的准确率曲线,标签是 acc
plt.plot(res.history['accuracy'], label='accuracy')
# 绘制模型训练过程中的平均准确率曲线,标签是 val_acc
plt.plot(res.history['val_accuracy'], label='val_accuracy')
# 绘制图例,展示出每个数据对应的图像名称,图例的放置位置为默认值。
plt.legend()
# 展示图片
plt.show()

4. 模型预测——调用模型的 evaluate()或者 predict() 等函数对新数据进行预测。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def load_and_model_prediction(validation_generator):
"""
加载模型和模型评估,打印验证集的 loss 和准确度
:param validation_generator: 预测数据
:return:
"""
# 加载模型
model = load_model('results/dnn.h5')
# 获取验证集的 loss 和 accuracy
loss, accuracy = model.evaluate_generator(validation_generator)
print("\nLoss: %.2f, Accuracy: %.2f%%" % (loss, accuracy * 100))

# 打印模型评估的结果
load_and_model_prediction(validation_generator)

(预测可视化):

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
from keras.models import load_model

def plot_load_and_model_prediction(validation_generator, labels):
"""
加载模型、模型预测并展示模型预测结果等
:param validation_generator: 预测数据
:param labels: 数据标签
:return:
"""
# 加载模型
model = load_model('results/dnn.h5')
# 测试集数据与标签
test_x, test_y = validation_generator.__getitem__(2)
# 预测值
preds = model.predict(test_x)
# 绘制预测图像的预测值和真实值,定义画布
plt.figure(figsize=(16, 16))
for i in range(16):
# 绘制各个子图
plt.subplot(4, 4, i + 1)
# 图片名称
plt.title(
'pred:%s / truth:%s' % (labels[np.argmax(preds[i])], labels[np.argmax(test_y[i])]))
# 展示图片
plt.imshow(test_x[i])

# 展示模型预测结果
plot_load_and_model_prediction(validation_generator, labels)

5. 使用模型

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
29
30
31
32
33
34
35
36
import os
from keras.models import load_model
from keras.preprocessing import image
import numpy as np

def load_and_predict(img):
"""
加载模型并预测一张图片的类别
:param img: PIL.Image 对象
:return: string, 模型识别图片的类别,
共 'cardboard','glass','metal','paper','plastic','trash' 6 个类别
"""
# 加载模型, 默认'results/dnn.h5',请填写你的最佳模型
model_path = 'results/dnn.h5'
model = load_model(model_path)
# 把图片转换成为numpy数组
img = image.img_to_array(img)
# 图片放缩
img = 1.0/255 * img
# expand_dims的作用是把img.shape转换成(1, img.shape[0], img.shape[1], img.shape[2])
x = np.expand_dims(img, axis=0)
# 模型预测, y: [[0.22421867 0.13031775 0.15167782 0.15904953 0.21509506 0.11964121]]
y = model.predict(x)
# 获取labels
labels = {0: 'cardboard', 1: 'glass', 2: 'metal', 3: 'paper', 4: 'plastic', 5: 'trash'}
# 获取输入图片的类别
y_predict = labels[np.argmax(y)]
# 返回图片的类别
return y_predict

from keras.preprocessing import image
# 输入图片路径和名称
file_path = 'test.jpg'
# 打印该张图片的类别
img = image.load_img(file_path)
print(load_and_predict(img))

Mycode

编写 数据处理创建模型训练模型保存模型评估模型 等部分的代码

完成模型

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
def processing_data(data_path):
"""
数据处理
:param data_path: 数据集路径
:return: train, test:处理后的训练集数据、测试集数据
"""
# -------------------------- 实现数据处理部分代码 ----------------------------

# ------------------------------------------------------------------------
train_data, test_data = None, None
return train_data, test_data


def model(train_data, test_data, save_model_path):
"""
创建、训练和保存深度学习模型
:param train_data: 训练集数据
:param test_data: 测试集数据
:param save_model_path: 保存模型的路径和名称
:return:
"""
# --------------------- 实现模型创建、训练和保存等部分的代码 ---------------------

# 保存模型(请写好保存模型的路径及名称)
# -------------------------------------------------------------------------

return model


def evaluate_mode(test_data, save_model_path):
"""
加载模型和评估模型
可以实现,比如: 模型训练过程中的学习曲线,测试集数据的loss值、准确率及混淆矩阵等评价指标!
主要步骤:
1.加载模型(请填写你训练好的最佳模型),
2.对自己训练的模型进行评估

:param test_data: 测试集数据
:param save_model_path: 加载模型的路径和名称,请填写你认为最好的模型
:return:
"""
# ----------------------- 实现模型加载和评估等部分的代码 -----------------------

# ---------------------------------------------------------------------------


def main():
"""
深度学习模型训练流程,包含数据处理、创建模型、训练模型、模型保存、评价模型等。
如果对训练出来的模型不满意,你可以通过调整模型的参数等方法重新训练模型,直至训练出你满意的模型。
如果你对自己训练出来的模型非常满意,则可以提交作业!
:return:
"""
data_path = None # 数据集路径
save_model_path = None # 保存模型路径和名称

# 获取数据
train_data, test_data = processing_data(data_path)

# 创建、训练和保存模型
model(train_data, test_data, save_model_path)

# 评估模型
evaluate_mode(test_data, save_model_path)


if __name__ == '__main__':
main()

模型预测

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
from keras.models import load_model
from keras.preprocessing import image
import numpy as np
import os


# -------------------------- 请加载您最满意的模型 ---------------------------
# 加载模型(请加载你认为的最佳模型)
# 加载模型,加载请注意 model_path 是相对路径, 与当前文件同级。
# 如果你的模型是在 results 文件夹下的 dnn.h5 模型,则 model_path = 'results/dnn.h5'
model_path = None

# 加载模型,如果采用keras框架训练模型,则 model=load_model(model_path)
model = None

# ---------------------------------------------------------------------------

def predict(img):
"""
加载模型和模型预测
主要步骤:
1.图片处理
2.用加载的模型预测图片的类别
:param img: PIL.Image 对象
:return: string, 模型识别图片的类别,
共 'cardboard','glass','metal','paper','plastic','trash' 6 个类别
"""
# -------------------------- 实现模型预测部分的代码 ---------------------------
# 获取图片的类别,共 'cardboard','glass','metal','paper','plastic','trash' 6 个类别
# 把图片转换成为numpy数组
img = image.img_to_array(img)


# 获取输入图片的类别
y_predict = None

# -------------------------------------------------------------------------

# 返回图片的类别
return y_predict



# --------------------------使用-----------------------------
from keras.preprocessing import image
# 输入图片路径和名称
img_path = 'test.jpg'
# 打印该张图片的类别
img = image.load_img(img_path)
print(predict(img))

Mo项目上代码-> accuracy为56%

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
import torch
from torch import nn
import random
import numpy as np
from PIL import Image
from torchvision.transforms import transforms
import torchvision.transforms.functional as TF
import os
import torch.utils.data as Data
import torchvision


class MyCNN(nn.Module):
def __init__(self, image_size, num_classes):
super(MyCNN, self).__init__()
# conv1: Conv2d -> BN -> ReLU -> MaxPool
self.conv1 = nn.Sequential(
nn.Conv2d(in_channels=3, out_channels=16, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(16),
nn.ReLU(),
nn.MaxPool2d(kernel_size=2, stride=2),
)
# conv2: Conv2d -> BN -> ReLU -> MaxPool
self.conv2 = nn.Sequential(
nn.Conv2d(in_channels=16, out_channels=32, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(32),
nn.ReLU(),
nn.MaxPool2d(kernel_size=2, stride=2),
)
# fully connected layer
self.fc = nn.Linear(32 * (image_size // 4) * (image_size // 4), num_classes)


def forward(self, x):
"""
input: N * 3 * image_size * image_size
output: N * num_classes
"""
x = self.conv1(x)
x = self.conv2(x)
# view(x.size(0), -1): change tensor size from (N ,H , W) to (N, H*W)
x = x.view(x.size(0), -1)
output = self.fc(x)
return output


def load_model(model_path, device):
net = MyCNN(32,6)
print('loading the model from %s' % model_path)
state_dict = torch.load(model_path, map_location=str(device))
if hasattr(state_dict, '_metadata'):
del state_dict._metadata
net.load_state_dict(state_dict)
return net


# 加载模型,加载请注意 model_path 是相对路径, 与当前文件同级。
# 如果你的模型是在 results 文件夹下的 dnn.h5 模型,则 model_path = 'results/dnn.h5'
model_path = 'results/cnn.pth'
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = load_model(model_path, device).to(device)
model.eval()


def predict(img):
"""
:param img: PIL.Image 对象
:return: string, 模型识别图片的类别,
共 'cardboard','glass','metal','paper','plastic','trash' 6 个类别
"""
transform = transforms.Compose([transforms.RandomCrop(size=(384,512), padding=10),
transforms.Resize((32,32)),
transforms.ToTensor(),
transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])
])
img = transform(img)

classes=['glass','paper','carboard','plastic','metal','trash']

img = img.to(device).unsqueeze(0)
pred_cate = model(img)
preds = pred_cate.argmax(dim=1)
# -------------------------------------------------------------------------
y_predict = classes[preds]

# 返回图片的类别
return y_predict

VGG16代码:accurary:92%

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
###############################################################################
# 重要: 请务必把任务(jobs)中需要保存的文件存放在 results 文件夹内
# Important : Please make sure your files are saved to the 'results' folder
# in your jobs
###############################################################################
# ------------------------------------------提交内容-----------------------------------
from keras.layers import Input, Dense, Flatten, Dropout, Activation
from keras.layers.normalization import BatchNormalization
from keras.preprocessing.image import ImageDataGenerator
from keras.callbacks import TensorBoard
from keras.preprocessing import image
from keras.models import load_model
from keras.models import Model
import matplotlib.pyplot as plt
import glob, os, cv2, random,time
import numpy as np
from keras.models import Sequential
from keras.layers import Conv2D,Flatten,MaxPooling2D,Dense
from keras.optimizers import SGD
from keras.applications.vgg16 import VGG16

def processing_data(data_path):
"""
数据处理
:param data_path: 数据集路径
:return: train, test:处理后的训练集数据、测试集数据
"""
train_data = ImageDataGenerator(
# 对图片的每个像素值均乘上这个放缩因子,把像素值放缩到0和1之间有利于模型的收敛
rescale=1. / 225,
# 浮点数,剪切强度(逆时针方向的剪切变换角度)
shear_range=0.1,
# 随机缩放的幅度,若为浮点数,则相当于[lower,upper] = [1 - zoom_range, 1+zoom_range]
zoom_range=0.1,
# 浮点数,图片宽度的某个比例,数据提升时图片水平偏移的幅度
width_shift_range=0.1,
# 浮点数,图片高度的某个比例,数据提升时图片竖直偏移的幅度
height_shift_range=0.1,
# 布尔值,进行随机水平翻转
horizontal_flip=True,
# 布尔值,进行随机竖直翻转
vertical_flip=True,
# 在 0 和 1 之间浮动。用作验证集的训练数据的比例
validation_split=0.1
)

# 接下来生成测试集,可以参考训练集的写法
validation_data = ImageDataGenerator(
rescale=1. / 255,
validation_split=0.1)

train_generator = train_data.flow_from_directory(
# 提供的路径下面需要有子目录
data_path,
# 整数元组 (height, width),默认:(256, 256)。 所有的图像将被调整到的尺寸。
target_size=(150, 150),
# 一批数据的大小
batch_size=16,
# "categorical", "binary", "sparse", "input" 或 None 之一。
# 默认:"categorical",返回one-hot 编码标签。
class_mode='categorical',
# 数据子集 ("training" 或 "validation")
subset='training',
seed=0)
validation_generator = validation_data.flow_from_directory(
data_path,
target_size=(150, 150),
batch_size=16,
class_mode='categorical',
subset='validation',
seed=0)

return train_generator, validation_generator

def model(train_generator, validation_generator, save_model_path):
"""
模型的建立
本次实验采用Vgg16模型
"""
vgg16_model = VGG16(weights='imagenet',include_top=False, input_shape=(150,150,3))
top_model = Sequential()
top_model.add(Flatten(input_shape=vgg16_model.output_shape[1:]))
top_model.add(Dense(256,activation='relu'))
top_model.add(Dropout(0.5))
top_model.add(Dense(6,activation='softmax'))

model = Sequential()
model.add(vgg16_model)
model.add(top_model)
# 编译模型, 采用 compile 函数: https://keras.io/models/model/#compile
model.compile(
# 是优化器, 主要有Adam、sgd、rmsprop等方式。
optimizer=SGD(lr=1e-3,momentum=0.9),
# 损失函数,多分类采用 categorical_crossentropy
loss='categorical_crossentropy',
# 是除了损失函数值之外的特定指标, 分类问题一般都是准确率
metrics=['accuracy'])

model.fit_generator(
# 一个生成器或 Sequence 对象的实例
generator=train_generator,
# epochs: 整数,数据的迭代总轮数。
epochs=200,
# 一个epoch包含的步数,通常应该等于你的数据集的样本数量除以批量大小。
steps_per_epoch=2259 // 16,
# 验证集
validation_data=validation_generator,
# 在验证集上,一个epoch包含的步数,通常应该等于你的数据集的样本数量除以批量大小。
validation_steps=248 // 16,
)
model.save(save_model_path)

return model

def evaluate_mode(validation_generator, save_model_path):
# 加载模型
model = load_model('results/Ynnex1.h5')
# 获取验证集的 loss 和 accuracy
loss, accuracy = model.evaluate_generator(validation_generator)
print("\nLoss: %.2f, Accuracy: %.2f%%" % (loss, accuracy * 100))

def predict(img):
"""
加载模型和模型预测
主要步骤:
1.加载模型(请加载你认为的最佳模型)
2.图片处理
3.用加载的模型预测图片的类别
:param img: PIL.Image 对象
:return: string, 模型识别图片的类别,
共 'cardboard','glass','metal','paper','plastic','trash' 6 个类别
"""
# 把图片转换成为numpy数组
img = img.resize((150, 150))
img = image.img_to_array(img)

# 加载模型,加载请注意 model_path 是相对路径, 与当前文件同级。
# 如果你的模型是在 results 文件夹下的 dnn.h5 模型,则 model_path = 'results/dnn.h5'
model_path = 'results/Ynnex1.h5'
try:
# 作业提交时测试用, 请勿删除此部分
model_path = os.path.realpath(__file__).replace('main.py', model_path)
except NameError:
model_path = './' + model_path

# -------------------------- 实现模型预测部分的代码 ---------------------------
# 加载模型
model = load_model(model_path)
# expand_dims的作用是把img.shape转换成(1, img.shape[0], img.shape[1], img.shape[2])
x = np.expand_dims(img, axis=0)
# 模型预测
y = model.predict(x)
# 获取labels
labels = {0: 'cardboard', 1: 'glass', 2: 'metal', 3: 'paper', 4: 'plastic', 5: 'trash'}
# -------------------------------------------------------------------------
predict = labels[np.argmax(y)]

# 返回图片的类别
return predict

def main():
"""
深度学习模型训练流程,包含数据处理、创建模型、训练模型、模型保存、评价模型等。
如果对训练出来的模型不满意,你可以通过调整模型的参数等方法重新训练模型,直至训练出你满意的模型。
如果你对自己训练出来的模型非常满意,则可以提交作业!
:return:
"""
data_path = "./datasets/la1ji1fe1nle4ishu4ju4ji22-momodel/dataset-resized" # 数据集路径
save_model_path = 'results/Ynnex1.h5' # 保存模型路径和名称
# 获取数据
train_generator, validation_generator = processing_data(data_path)
# 创建、训练和保存模型
model(train_generator, validation_generator, save_model_path)
# 评估模型
evaluate_mode(validation_generator, save_model_path)


# 数据测试
def test_result():
import random,cv2
import numpy as np
import matplotlib.pyplot as plt

from PIL import Image

# 导入相关包
import glob, os

# 数据集路径
data_path = "./datasets/la1ji1fe1nle4ishu4ju4ji22-momodel/dataset-resized"

# 获取数据名称列表
img_list = glob.glob(os.path.join(data_path, '*/*.jpg'))

# 打印数据集总量
print("数据集总数量:", len(img_list))
print("数据路径和名称:",img_list[0])
# 从数据名称列表 img_list 中随机选取 6 个。
for i, img_path in enumerate(random.sample(img_list, 6)):

# 读取图片
img = cv2.imread(img_path)

# 将图片从 BGR 模式转为 RGB 模式
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img = Image.fromarray(img)
plt.imshow(img)
plt.show()
res = predict(img)
print(res)


if __name__ == '__main__':
# main()
test_result()

VGG16说明:https://baijiahao.baidu.com/s?id=1667221544796169037&wfr=spider&for=pc

附录

CSDN

Github

Author: Mrli

Link: https://nymrli.top/2020/12/11/浙大2020春夏-人工智能习题2——垃圾分类/

Copyright: All articles in this blog are licensed under CC BY-NC-SA 3.0 unless stating additionally.

< PreviousPost
UML简单记录
NextPost >
细品单例模式
CATALOG
  1. 1. 1. 实验介绍
    1. 1.1. 1.1 实验背景
    2. 1.2. 1.2 实验要求
    3. 1.3. 1.3 实验环境
  2. 2. 2.实验内容
    1. 2.1. 2.1 介绍数据集
    2. 2.2. 2.2 图片预处理
    3. 2.3. 2.3 采用 Keras 建立一个简单的深度神经网络模型
      1. 2.3.1. 1. 定义模型——创建一个模型并添加配置层
      2. 2.3.2. 2. 编译模型——指定损失函数和优化器,并调用模型的 compile() 函数,完成模型编译。
      3. 2.3.3. 3. 训练模型——通过调用模型的 fit() 函数来训练模型。
      4. 2.3.4. 4. 模型预测——调用模型的 evaluate()或者 predict() 等函数对新数据进行预测。
      5. 2.3.5. 5. 使用模型
  3. 3. Mycode
    1. 3.1. 完成模型
    2. 3.2. 模型预测
      1. 3.2.1. Mo项目上代码-> accuracy为56%
  4. 4. 附录
    1. 4.1. CSDN
    2. 4.2. Github