Visual Studio Code实现简单的服装图片分类

简介:

        本教程的代码使用 神经网络来训练可以对手写数字 0-9 进行分类的图像分类机器学习模型。 它通过创建一个神经网络来实现此目的。该神经网络将“28 像素 x 28 像素”图像的像素值作为输入,输出一个包含 10 个概率的列表,一个概率对应于要分类的一个数字。 下面是数据的外观示例。

一,读取数据

        首先导入神经网络集所需要的包,其中keras层方式做前向传播,服装图片分类每一张图片28*28,xy中保存训练集的图像和目标。x_testy_test中保存测试集需要的图像和目标。

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import datasets,layers,optimizers,Sequential,metrics
import os 
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
 #(1)导入数据集,数组类型
(x,y),(x_test,y_test) = datasets.fashion_mnist.load_data()
# 查看数据集信息
print(f'x.shape={x.shape},y.shape={y.shape}') # 查看训练集xy的大小
print(f'x_test.shape={x_test.shape},y_test.shape={y_test.shape}') #查看测试集的大小
print(f'y[:5]={y[:5]}') # 查看y的前5项数据

         读取的数据集如下,变量x中有60k张图片,每张图片的都是28*28的大小,其中变量y保存的是每张图片属于哪个分类。如,y[:5]=[9 0 0 3 0],第一张图片属于第10个类别,第二张图片属于第0个类别。

        我们为了能让这个数据集可以更直接的认识,将图片信息绘制出来展示前10张图像。

# 数据集展示
import matplotlib.pyplot as plt
import numpy as np
class_names = ['Tshirt','Trouser','Pullover','Dress','Coat','Sandal','Shirt','Sneaker','Bag','Ankle boot']
# 绘制图像
for i in range(0,10):
    plt.subplot(2,5,i+1)
    plt.imshow(x[i]) 
    plt.xlabel(class_names[y[i]]) #y[i]代表所属分类的标签值
    plt.xticks([]) 
    plt.yticks([])

 

二,数据集加载

        在数据加载时我们首先要对训练集的目标值y进行one-hot编码,有利于后面的预测结果计算损失。以标量变成向量,其对应的数值变成1。如编码前y[0]=9,第一张图片对应的分类是第9类,编码后y[0]=[0., 0., 0., 0., 0., 0., 0., 0., 0., 1.],第9个索引对应的值变成1,其他值都是0。

        使用ds_train创建一个数据集,将自动输入的x和y转换为tensor类型。

        使用map()函数对数据集中的所有元素执行函数内容,使用batch()函数指定每次代从数据集中取多少个数据,shuffle()打乱数据集,但不改变xy的对应关系,避免结果出现偶然性。

        在对训练集预处理的时候,不需要对y_test数据进行one-hot编码,因为在怎么编码测试的结果都是一个值,和y_test比较,测试是不是相同就好了。

def processing(x,y):
    x = tf.cast(x,tf.float32)/255.0  
    y = tf.cast(y,tf.int32)  
    return(x,y)
 
#(2)数据加载
y = tf.one_hot(y,depth=10)  
ds_train = tf.data.Dataset.from_tensor_slices((x,y))
ds_train = ds_train.map(processing).batch(128).shuffle(10000) # 设置每次采样大小,并打乱
# 对测试集预处理
ds_test = tf.data.Dataset.from_tensor_slices((x_test,y_test))
ds_test = ds_test.map(processing).batch(128) #一次测试完所有测试集样本呢,不需要打乱
 
# 生成迭代器,检测数据加载是否正确
sample = next(iter(ds_train)) 
print('x_batch:',sample[0].shape,'y_batch:',sample[1].shape) 

         为了查看我们预处理的数据是否正确,我们来构建一个迭代器来查看,起检验作用。iter()函数生成一个迭代器,每执行一次next()函数,从ds_train中获取一组batch的样本(x,y),sample[0]保存x的数据,sample[1]保存y的数据。

 

三,网络构建

        在网络构建模型中,使用堆层的方法构建全连接层tf.keras.Sequential(),使用 tf.keras.layers.Dense()添加每一层,构建5层的全连接层,指定激活函数为relu函数,使网络的维度从[b,28*28]变换到最终的[b,10],即输出10个分类的结果。

#(3)构建网络
# [b,784]=>[b,256]=>[b,128]=>[b,64]=>[b,32]=>[b,10],中间层一般从大到小降维
model = Sequential([
    layers.Dense(256, activation=tf.nn.relu), #第一个连接层,输出256个特征
    layers.Dense(128, activation=tf.nn.relu), #第二个连接层
    layers.Dense(64, activation=tf.nn.relu), #第三个连接层
    layers.Dense(32, activation=tf.nn.relu), #第四个连接层
    layers.Dense(10), #最后一层不需要激活函数,输出10个分类
    ])
model.build(input_shape=[None, 28*28])
model.summary()
# 完成权重更新 w = w - lr * grad
optimizer = optimizers.Adam(lr=1e-3) 

        通过运行得出的网络结果如下, param代表每一层的参数个数,以最后一层为例,权重w的shape为[32,10],偏置b的shape为[10],参数个数为32*10+10=330。

四,网络集的训练

        在网络集的训练中我们设置整个网络循环20次,接下来计算损失函数,使用交叉熵更新权重偏置。使用优化器更新梯度,相当于计算w1 = w1 - lr * grads[0],并原地更新权重偏置不改变数据类型。

for epoch in range(20): # 运行20次
    for step,(x,y) in enumerate(ds_train):
        # ds_train中x的shape是[b,28,28],由于输入层是[b,28*28],需要类型转换
        x = tf.reshape(x, [-1, 28*28]) #-1会自动结算第0维
        # 梯度计算
        with tf.GradientTape() as tape:
            # 网络自动运行:[b,784]=>[b,10]
            logits = model(x) #得到最后一层的输出
            loss1 = tf.reduce_mean(tf.losses.MSE(y, logits)) 
            # 计算交叉熵损失,真实值y(onehot编码后的)和输出概率(logits会自动进行softmax变成概率值)
            loss2 = tf.reduce_mean(tf.losses.categorical_crossentropy(y, logits, from_logits=True))
            
        # 梯度计算,
        grads = tape.gradient(loss2, model.trainable_variables) 
        # 更新权重,zip将grads的元素和model.trainable_variables中的元素结合在一起
        optimizer.apply_gradients(zip(grads, model.trainable_variables)) # 完成任务:w1.assign_sub(lr * grads[0])
        if step % 100 == 0:
            print(f'epochs:{epoch}, step:{step}, loss_MSE:{loss1}, loss_CE:{loss2}')

五,测试网络集

        在网络训练中是在20次的大循环内部的,使用总预测对了的个数除以总测试样本数来计算模型准确率。同样,每次迭代从测试集中取batch个样本,放入网络计算,得到输出层的结果logits需要求预测结果概率最大值所在下标,知道了下标索引也就知道了每个测试样本属于第几个分类。

#(6)网络测试
    total_correct = 0 # 总预测对了的个数
    total_sum = 0 # 总统计的个数
    for (x,y) in ds_test: #返回测试集的x和y
        x = tf.reshape(x, [-1,28*28]) 
        logits = model(x)
        # 计算概率最大的值所在的索引        
        # 将logits转换为probility
        prob = tf.nn.softmax(logits, axis=1) # 在最后一个维度上转换概率,且概率和为1
        predict = tf.argmax(prob, axis=1) # 找到最大值所在位置,得到一个标量
        
        # y 是int32类型,shape为[128]
        # predict 是int64类型,shape为[128]
        predict = tf.cast(predict, dtype=tf.int32)
        # 只要看两个变量的值是否相同
        correct = tf.equal(y, predict) #返回True和False
        # True和False变成1和0,统计1的个数,一共有多少个预测对了
        correct = tf.reduce_sum(tf.cast(correct, dtype=tf.int32))
        total_correct += int(correct) 
        total_sum += x.shape[0]
    
    # 计算一次大循环之后的模型准确率
    acc = total_correct/total_sum
    print(f'acc: {acc}')

六,整体运行展示

        该模型运行结果如下:第一次循环,以及经过20次循环的结果的出的结果是,第二十次循环的结果为:0.893。 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值