完全に接続されたニューラルネットワークを使用した車両認識

import os
import zipfile
import random
import paddle
import numpy as np
import matplotlib.pyplot as plt
import PIL.Image as Image
from paddle.io import Dataset

(1) OS のインポート: ファイル システムと対話し、システム コマンドを実行し、環境変数を管理する方法を提供するオペレーティング システム (OS) モジュールをインポートします。
(2)import zipfile: zip アーカイブを処理するためのツールを提供するインポート モジュール。
(3) インポートランダム: 乱数、ランダムシーケンスを生成し、シーケンスからランダムな要素を選択する機能を提供するインポートモジュールです。ランダム
(4)インポート パドル: 機械学習モデルを開発およびトレーニングするための包括的なツール セットを提供するオープンソースの深層学習プラットフォームであるインポート モジュール。パドル
(5)import numpy as np: モジュールをインポートし、np としてエイリアスします。これは、配列、行列、その他の数学演算を処理するためのツールを提供する Python の一般的な数値計算ライブラリです。numpy
(6)import matplotlib.pyplot as plt: これは、折れ線グラフ、散布図、ヒストグラムなどの視覚化を作成するためのツールを提供する Python プロット ライブラリです。matplotlib.pyplot
(7)import PIL.Image: これは Python Imaging Library (PIL) の一部であり、画像ファイルを処理するためのツールを提供します。PIL.Image
(8) from paddle.io import Dataset: PaddlePaddle でデータセットを処理するためのツールを提供するパッケージからモジュールをインポートします。データのロード、前処理、反復など。


'''
参数配置
'''
train_parameters = {
    "input_size": [3, 120, 120],                             #输入图片的shape
    "class_dim": 3,                                               #分类数
    "src_path":"/home/aistudio/data/data72920/Data.zip",     #原始数据集路径
    "target_path":"/home/aistudio/work/",                    #要解压的路径
    "train_list_path": "/home/aistudio/data/train.txt",      #train.txt路径
    "eval_list_path": "/home/aistudio/data/eval.txt",        #eval.txt路径
    "label_dict":{'0':'汽车','1':'摩托车','2':'货车'},        #标签字典
    "num_epochs": 3,                                        #训练轮数
    "train_batch_size": 8,                                   #训练时每个批次的大小
    "learning_strategy": {                                   #优化函数相关的配置
        "lr": 0.1                                          #超参数学习率
    }, 
    'skip_steps': 50,                                        #每N个批次打印一次结果
    'save_steps': 500,                                       #每N个批次保存一次模型参数
    "checkpoints": "/home/aistudio/work/checkpoints"         #保存的路径
}

1. データの準備

(1) 元のデータセットを解凍する
(2) トレーニングセットと検証セットを比率に従って分割する
(3) 順序を入れ替えてデータリストを生成する
(4) データリーダーを定義する


#解压原始数据集
def unzip_data(src_path,target_path):
    '''
    解压原始数据集,将src_path路径下的zip包解压至target_path目录下
    '''
    if(not os.path.isdir(os.path.join(target_path,'Data'))):     
        z = zipfile.ZipFile(src_path, 'r')
        z.extractall(path=target_path)
        z.close()
        print('数据集解压完成')
    else:
        print('文件已存在')

このコードは、src_path と target_path の 2 つのパラメーターを取る unzip_data という関数を定義します。

def get_data_list(target_path, train_list_path, eval_list_path):
    '''
    生成数据列表
    '''
    data_dir = 'work/Data'     #这会将变量设置为包含数据的目录的路径。data_dir
    all_data_list  = []             #这将初始化一个名为的空列表,该列表将用于存储数据路径及其相应的标签。
    for im in os.listdir(data_dir):  #这将循环访问 指定的目录中的所有文件
        img_path = os.path.join(data_dir, im)  #通过联接图像和文件名来构造图像文件的完整路径
        img_label = str(int(im.split('_')[0])-1)  #假定标签是文件名的第一部分,下划线之前
        all_data_list.append(img_path + '\t' + img_label + '\n')  #这会附加一个字符串,其中包含图像路径,后跟制表符 ,后跟标签和换行符。
        
    # 对训练列表进行乱序
    random.shuffle(all_data_list) #随机洗牌列表,为了防止模型在训练期间记住数据的顺序。
    with open(train_list_path, 'a') as f1:   #这将在追加模式下打开两个文件。用于确保文件在使用后正确关闭。
        with open(eval_list_path, 'a') as f2:
            for ind, img_path_label in enumerate(all_data_list): #循环并将每个元素分配变量,并将索引分配给变量。
                #划分测试集和训练集
                if ind % 10 == 0: #这会将 的每个元素写入,具体取决于值。每 10个元素写入 ,其余元素写入
                    f2.write(img_path_label) 
                else:
                    f1.write(img_path_label)
    print ('生成数据列表完成!')

#参数初始化
src_path=train_parameters['src_path']
target_path=train_parameters['target_path']
train_list_path=train_parameters['train_list_path']
eval_list_path=train_parameters['eval_list_path']

#解压原始数据到指定路径
unzip_data(src_path,target_path)

#每次生成数据列表前,首先清空train.txt和eval.txt
with open(train_list_path, 'w') as f: 
    f.seek(0)
    f.truncate() 
with open(eval_list_path, 'w') as f: 
    f.seek(0)
    f.truncate()     

#生成数据列表   
get_data_list(target_path,train_list_path,eval_list_path)

#参数初始化
src_path=train_parameters['src_path']
target_path=train_parameters['target_path']
train_list_path=train_parameters['train_list_path']  #此代码使用源数据、目标目录以及训练和评估数据列表
eval_list_path=train_parameters['eval_list_path']   #的文件路径的路径初始化变量。

#解压原始数据到指定路径
unzip_data(src_path,target_path)

#每次生成数据列表前,首先清空train.txt和eval.txt
with open(train_list_path, 'w') as f: 
    f.seek(0)
    f.truncate() 
with open(eval_list_path, 'w') as f: 
    f.seek(0)
    f.truncate()     
#生成数据列表   
get_data_list(target_path,train_list_path,eval_list_path)

此代码定义了一个名为的 PyTorch 数据集类,该类可用于函数生成的训练或评估数据列表中加载图像和标签。
class dataset(Dataset):
    def __init__(self, data_path, mode='train'): #此代码为采用两个参数的类定义初始化方法
        """
        数据读取器
        :param data_path: 数据集所在路径
        :param mode: train or eval
        """
        super().__init__()   #此代码调用继承自的类的初始化方法
        #这些行定义类的实例变量,包含训练和评估数据列表的目录的路径,存储图像文件路径的列表,存储相应标签的列表。
        self.data_path = data_path  
        self.img_paths = []
        self.labels = []
#这些行根据 mode的值读取训练或评估数据列表中,并使用图像的文件路径和相应标签填充img和lable列表。
        if mode == 'train':
            with open(os.path.join(self.data_path, "train.txt"), "r", encoding="utf-8") as f:
                self.info = f.readlines()
            for img_info in self.info:
                img_path, label = img_info.strip().split('\t')
                self.img_paths.append(img_path)
                self.labels.append(int(label))

        else:
            with open(os.path.join(self.data_path, "eval.txt"), "r", encoding="utf-8") as f:
                self.info = f.readlines()
            for img_info in self.info:
                img_path, label = img_info.strip().split('\t')
                self.img_paths.append(img_path)
                self.labels.append(int(label))

 # 此代码定义了类的方法,PyTorch DataLoader 调用该方法以检索给定索引的特定图像和标签。
    def __getitem__(self, index):
        """
        获取一组数据
        :param index: 文件索引号
        :return:
        """
        # 第一步打开图像文件并获取label值
        #此代码检索与给定索引对应的图像的文件路径
        img_path = self.img_paths[index]
        img = Image.open(img_path)
        if img.mode != 'RGB':
            img = img.convert('RGB') 
        img = np.array(img).astype('float32')
        img = img.transpose((2, 0, 1)) / 255
        label = self.labels[index]
        label = np.array([label], dtype="int64")
        return img, label

    def print_sample(self, index: int = 0):
        print("文件名", self.img_paths[index], "\t标签值", self.labels[index])
    def __len__(self):
        return len(self.img_paths)

#训练数据加载
train_dataset = dataset('/home/aistudio/data',mode='train')
train_loader = paddle.io.DataLoader(train_dataset, 
                                    batch_size=train_parameters['train_batch_size'], 
                                    shuffle=True
                                    )
#测试数据加载
eval_dataset = dataset('/home/aistudio/data',mode='eval')
eval_loader = paddle.io.DataLoader(eval_dataset,
                                   batch_size=train_parameters['train_batch_size'], 
                                   shuffle=False
                                   )
                                   #在这里,batch_size 参数用于指定每个 batch 的数据大小,shuffle 参数用于打乱数据集。

2. モデル構成

class MyDNN(paddle.nn.Layer):
	def __init__(self):
		super(MyDNN,self).__init__()
		self.linear1 = paddle.nn.Linear(in_features=3*120*120, out_features=4096) # 定义了一个全连接层 linear1,输入维度为 3*120*120,输出维度为 4096。
		self.relu1 = paddle.nn.ReLU() # 定义了一个激活函数 relu1,使用 ReLU 激活函数。
		self.linear2 = paddle.nn.Linear(in_features=4096, out_features=2048) #定义了一个全连接层 linear2,输入维度为 4096,输出维度为 2048。
		self.relu2 = paddle.nn.ReLU()  #  定义了一个激活函数 relu2,使用 ReLU 激活函数。
		self.linear3 = paddle.nn.Linear(in_features=2048, out_features=3)  # 定义了一个全连接层 linear3,输入维度为 2048,输出维度为 3。
		
def forward(self,input): # forward 定义执行实际运行时网络的执行逻辑、前向传播
		# input.shape (8, 3, 120, 120)
		x = paddle.reshape(input, shape=[-1,3*120*120]) #-1 表示这个维度的值是从 x
的元素总数和剩余维度推断出来的,有且只能有一个维度设置为-1
		# print(x.shape)
		x = self.linear1(x) # 将变换后的数据 x 传入 linear1 进行线性变换。
		x = self.relu1(x) # 将经过线性变换后的数据 x 传入 relu1 进行 ReLU 激活。
		x = self.linear2(x)
		x = self.relu2(x)
		y = self.linear3(x)
	return y # 返回y

このコードは、カスタム ニューラル ネットワーク クラス MyDNN を定義します。これは、paddle.nn.Layer から継承し、initメソッドと forward メソッドをオーバーライドします。

3. モデルのトレーニング

def draw_process(title,color,iters,data,label):
    plt.title(title, fontsize=24)
    plt.xlabel("iter", fontsize=20)
    plt.ylabel(label, fontsize=20)
    plt.plot(iters, data,color=color,label=label) 
    plt.legend()
    plt.grid()
    plt.show()

この関数は、トレーニング プロセス中にインジケーターの変化曲線を描くために使用されます。パラメーターの意味は次のとおりです:
title: 画像のタイトル。
color: 曲線の色。
iters: 横軸は反復数を表します。
データ: 縦軸は、各反復サイクルにおけるインジケーターの値を表します。
label: 縦軸のラベル。縦軸で表される特定の指標を説明するために使用されます。

model = MyDNN()  #定义模型
model.train()          #训练模型
cross_entropy = paddle.nn.CrossEntropyLoss() #定义损失函数
optimizer = paddle.optimizer.Adam(learning_rate=train_parameters['learning_strategy']['lr'],
                                  parameters=model.parameters())   #定义优化器
                                  
steps = 0 #初始化步数变量 steps,表示已经迭代的 batch 的数量,初始值为 0。

Iters, total_loss, total_acc = [], [], [] #创建三个空列表 Iters、total_loss 和 total_acc,用于记录迭代过程中的 batch 数量、损失和准确率。

for epo in range(train_parameters['num_epochs']):   # 使用 for 循环遍历每个 epoch,train_parameters['num_epochs'] 表示需要迭代 epoch 数量。
    for _, data in enumerate(train_loader()):  #迭代训练
        steps += 1 #将步数加 1,表示已经迭代的 batch 的数量。
        x_data = data[0]  #将数据 batch 中的输入和标签分别赋值给 x_data 和 y_data。
        y_data = data[1]
        predicts = model(x_data) #使用模型进行前向传递,并得到预测结果。
        loss = cross_entropy(predicts, y_data) #计算预测结果和真实标签之间的交叉熵损失。
        acc = paddle.metric.accuracy(predicts, y_data) #计算预测结果的准确率。
        loss.backward() #使用反向传播算法计算梯度。
        optimizer.step() #使用优化器更新模型参数。
        optimizer.clear_grad() #清空优化器中的梯度信息。
        if steps % train_parameters["skip_steps"] == 0: #如果当前步数可以被跳过的步骤数量整除,执行下面的代码。
            Iters.append(steps)
            total_loss.append(loss.numpy()[0])
            total_acc.append(acc.numpy()[0]) #将当前步数、损失和准确率的值添加到相应的列表中。
            #打印中间过程
            print('epo: {}, step: {}, loss is: {}, acc is: {}'\
                  .format(epo, steps, loss.numpy(), acc.numpy()))
        #保存模型参数
        if steps % train_parameters["save_steps"] == 0:
            save_path = train_parameters["checkpoints"]+"/"+"save_dir_" + str(steps) + '.pdparams'
            print('save model to: ' + save_path)
            paddle.save(model.state_dict(),save_path)
paddle.save(model.state_dict(),train_parameters["checkpoints"]+"/"+"save_dir_final.pdparams")
draw_process("trainning loss","red",Iters,total_loss,"trainning loss")
draw_process("trainning acc","green",Iters,total_acc,"trainning acc") #绘制训练过程中损失和准确率的图像。

このコードは、モデルをトレーニングするためのメイン プログラムです。

4. モデルの評価

model__state_dict = paddle.load('work/checkpoints/save_dir_final.pdparams')   #加载已经训练好的模型。
model_eval = MyDNN()
model_eval.set_state_dict(model__state_dict) 
model_eval.eval()

#代码对验证数据集进行迭代,对每个批次数据进行评估,并记录每个批次数据的准确率。这些准确率存储在 accs 列表中。
accs = []
for _, data in enumerate(eval_loader()):
    x_data = data[0]
    y_data = data[1]
    predicts = model_eval(x_data)
    acc = paddle.metric.accuracy(predicts, y_data)
    accs.append(acc.numpy()[0])
print('模型在验证集上的准确率为:',np.mean(accs)) #  代码计算并输出模型在验证集上的平均准确率。

5. モデル予測

def load_image(img_path):
    '''
    预测图片预处理
    '''
    img = Image.open(img_path)  #打开待预测图像
    # print(img.mode) 
    if img.mode != 'RGB':  
        img = img.convert('RGB') 
    img = img.resize((120, 120), Image.ANTIALIAS) #使用 resize 方法将图像大小重置为 120x120 像素
    img = np.array(img).astype('float32')  #将图像转换为 Numpy 数组,并将数据类型设置为 float32
    img = img.transpose((2, 0, 1)) / 255  # HWC to CHW 并像素归一化
    return img

# 予測対象画像を予測し、予測結果を出力する

model__state_dict = paddle.load('work/checkpoints/save_dir_final.pdparams') 
model_predict = MyDNN()
model_predict.set_state_dict(model__state_dict) 
model_predict.eval()
infer_path='work/车辆.png'
infer_img = Image.open(infer_path)
plt.imshow(infer_img)          #根据数组绘制图像
plt.show()                     #显示图像
#对预测图片进行预处理
infer_img = load_image(infer_path)
# print(type(infer_img))
infer_img = infer_img[np.newaxis,:, : ,:]  #reshape(-1,3,50,50)
infer_img = paddle.to_tensor(infer_img)
results = model_predict(infer_img)
print(results)
results = paddle.nn.functional.softmax(results)
print(results)
print("汽车:{:.2f},摩托车:{:.2f},货车:{:.2f}" .format(results.numpy()[0][0],
                                                    results.numpy()[0][1],
                                                    results.numpy()[0][2]))                                               

おすすめ

転載: blog.csdn.net/m0_56898461/article/details/130174552