本次实验使用老师发的雷达奇妙数据
实验要求
读取图像形式的MASTAR数据
1、划分数据集为test/train
2、归一化
题目1:定义并训练线性分类器的神经网络
注:本次老师的要求是不限方法,使用pytorch尽可能提升精度
1、准备函数
#本文用的pycharm写的,总共四个函数,本函数要被调用所以一定要交func.py
import torch
import torch.nn as nn
from torch.utils.data import TensorDataset, DataLoader
import os
import torch.optim as optim
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
'''
绘图
'''
def drawing(x,y,title):
plt.plot(x,y)
plt.title(title)
plt.show()
'''
获取数据集
'''
def get_data(train_dir):
train_images = []
train_labels = []
#对train文件夹进行遍历,读取train里面的十个文件夹,label就是文件夹名,也就是类别
for label in os.listdir(train_dir):
label_dir = os.path.join(train_dir, label)
# 检查是否为文件夹
if os.path.isdir(label_dir):
# 遍历当前标签对应的文件夹中的所有文件
for filename in os.listdir(label_dir):
if filename.endswith(('.jpg')):
file_path = os.path.join(label_dir, filename)
try:
# 打开图像文件
image = Image.open(file_path)
# 将图像添加到训练数据列表
train_images.append(image)
# 将对应的标签添加到标签列表
train_labels.append(label)
except Exception as e:
print(f"读取图像 {file_path} 时出错: {e}")
train_images = np.array(train_images)
train_labels = np.array(train_labels)
return train_images, train_labels
'''
进行网络的定义
'''
class net(nn.Module):
#定义神经网络有那些层,这一部分是输入的数据
def __init__(self):
super().__init__()
#三个参数矩阵和一个激活函数
self.w1=nn.Linear(128*128, 512)#输入28*28,输出512,linear包括了局部梯度
self.w2=nn.Linear(512, 512)
self.w3=nn.Linear(512, 10)#输出10,10个类
self.relu=nn.ReLU()#也不能自己写激活函数,因为也没有中间参数
#前向传播,确定init的积木怎么摆
def forward(self, x):
#数据展平要不然算不了。
#size表示该维度的大小会根据张量的总元素个数和其他指定维度的大小自动计算得出
x = x.view(x.size(0), -1)
x = self.w1 (x)
x = self.relu(x)
x = self.w2 (x)
x = self.relu(x)
x = self.w3 (x)
return x
'''
使用BN方法的网络
'''
class BN(nn.Module):
# 定义神经网络有哪些层,这一部分是输入的数据
def __init__(self):
super().__init__()
# 三个参数矩阵和一个激活函数
self.w1 = nn.Linear(128 * 128, 512) # 输入128*128,输出512,linear包括了局部梯度
# 在第一个全连接层后添加批量归一化层
self.bn1 = nn.BatchNorm1d(512)
self.w2 = nn.Linear(512, 512)
# 在第二个全连接层后添加批量归一化层
self.bn2 = nn.BatchNorm1d(512)
self.w3 = nn.Linear(512, 10) # 输出10,10个类
self.relu = nn.ReLU() # 也不能自己写激活函数,因为也没有中间参数
# 前向传播,确定init的积木怎么摆
def forward(self, x):
# 数据展平要不然算不了。
# size表示该维度的大小会根据张量的总元素个数和其他指定维度的大小自动计算得出
x = x.view(x.size(0), -1)
x = self.w1(x)
# 在第一个全连接层输出后使用批量归一化
x = self.bn1(x)
x = self.relu(x)
x = self.w2(x)
# 在第二个全连接层输出后使用批量归一化
x = self.bn2(x)
x = self.relu(x)
x = self.w3(x)
return x
'''
加深网络
'''
class deeped_BN(nn.Module):
def __init__(self):
super().__init__()
# 输入层到第一个隐藏层
self.w1 = nn.Linear(128 * 128, 512)
self.bn1 = nn.BatchNorm1d(512)
# 新增隐藏层
self.w2 = nn.Linear(512, 512)
self.bn2 = nn.BatchNorm1d(512)
self.w3 = nn.Linear(512, 512)
self.bn3 = nn.BatchNorm1d(512)
self.w4 = nn.Linear(512, 512)
self.bn4 = nn.BatchNorm1d(512)
# 输出层
self.w5 = nn.Linear(512, 10)
self.relu = nn.ReLU()
def forward(self, x):
# 数据展平
x = x.view(x.size(0), -1)
x = self.w1(x)
x = self.bn1(x)
x = self.relu(x)
x = self.w2(x)
x = self.bn2(x)
x = self.relu(x)
x = self.w3(x)
x = self.bn3(x)
x = self.relu(x)
x = self.w4(x)
x = self.bn4(x)
x = self.relu(x)
x = self.w5(x)
return x
'''
超级加深网络
'''
class ten_deeped_BN(nn.Module):
def __init__(self):
super().__init__()
# 输入层到第一个隐藏层,使用 BN
self.w1 = nn.Linear(128 * 128, 512)
self.bn1 = nn.BatchNorm1d(512)
# 第二个隐藏层,使用 BN
self.w2 = nn.Linear(512, 512)
self.bn2 = nn.BatchNorm1d(512)
# 后面八层不使用 BN
self.w3 = nn.Linear(512, 512)
self.w4 = nn.Linear(512, 512)
self.w5 = nn.Linear(512, 512)
self.w6 = nn.Linear(512, 512)
self.w7 = nn.Linear(512, 512)
self.w8 = nn.Linear(512, 512)
self.w9 = nn.Linear(512, 512)
self.w10 = nn.Linear(512, 512)
# 输出层
self.w11 = nn.Linear(512, 10)
self.relu = nn.ReLU()
def forward(self, x):
# 数据展平
x = x.view(x.size(0), -1)
# 前两层使用 BN
x = self.w1(x)
x = self.bn1(x)
x = self.relu(x)
x = self.w2(x)
x = self.bn2(x)
x = self.relu(x)
# 后面八层不使用 BN
x = self.w3(x)
x = self.relu(x)
x = self.w4(x)
x = self.relu(x)
x = self.w5(x)
x = self.relu(x)
x = self.w6(x)
x = self.relu(x)
x = self.w7(x)
x = self.relu(x)
x = self.w8(x)
x = self.relu(x)
x = self.w9(x)
x = self.relu(x)
x = self.w10(x)
x = self.relu(x)
# 输出层
x = self.w11(x)
return x
'''
评估模型准确率
'''
#使用已经有的模型进行预测,torch.no_grad的意思是禁止pytorch进行梯度计算
def val_model(test_loader,dir):
model_t = net()
model_t.load_state_dict(torch.load(dir))
model_t.eval() # 将模型设置成评估模式
correct = 0
total = 0
with torch.no_grad():
for images, labels in test_loader:
outputs = model_t(images)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
y_acc=100*correct/total
print(f'Accuracy on val set: {100 * correct / total}%')
return y_acc
'''
评估BN模型准确率
'''
#使用已经有的模型进行预测,torch.no_grad的意思是禁止pytorch进行梯度计算
def valBN_model(test_loader,dir):
model_t = BN()
model_t.load_state_dict(torch.load(dir))
model_t.eval() # 将模型设置成评估模式
correct = 0
total = 0
with torch.no_grad():
for images, labels in test_loader:
outputs = model_t(images)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
y_acc=100*correct/total
print(f'Accuracy on val set: {100 * correct / total}%')
return y_acc
'''
评估加深后的BN
'''
#使用已经有的模型进行预测,torch.no_grad的意思是禁止pytorch进行梯度计算
def val_deep_BN_model(test_loader,dir):
model_t = deeped_BN()
model_t.load_state_dict(torch.load(dir))
model_t.eval() # 将模型设置成评估模式
correct = 0
total = 0
with torch.no_grad():
for images, labels in test_loader:
outputs = model_t(images)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
y_acc=100*correct/total
print(f'Accuracy on val set: {100 * correct / total}%')
return y_acc
'''
评估10层的
'''
#使用已经有的模型进行预测,torch.no_grad的意思是禁止pytorch进行梯度计算
def val_tendeep_BN_model(test_loader,dir):
model_t = ten_deeped_BN()
model_t.load_state_dict(torch.load(dir))
model_t.eval() # 将模型设置成评估模式
correct = 0
total = 0
with torch.no_grad():
for images, labels in test_loader:
outputs = model_t(images)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
y_acc=100*correct/total
print(f'Accuracy on val set: {100 * correct / total}%')
return y_acc
'''
数据增强
'''
def augment_data(images, labels):
augmented_images = []
augmented_labels = []
for img, label in zip(images, labels):
# 原始图像
augmented_images.append(img)
augmented_labels.append(label)
# 水平向右平移
shift_right = 3
img_shifted_right = np.roll(img, shift_right, axis=1)
img_shifted_right[:, :shift_right] = 0 # 填充空白部分为 0
augmented_images.append(img_shifted_right)
augmented_labels.append(label)
# 水平向左平移
shift_left = 3
img_shifted_left = np.roll(img, -shift_left, axis=1)
img_shifted_left[:, :shift_right] = 0 # 填充空白部分为 0
augmented_images.append(img_shifted_left)
augmented_labels.append(label)
#翻转
flipped_img = np.fliplr(img)
augmented_images.append(flipped_img)
augmented_labels.append(label)
# 放大操作
scale_factor = 1.2 # 放大倍数
pil_img = Image.fromarray(img.astype(np.uint8))
width, height = pil_img.size
new_width = int(width * scale_factor)
new_height = int(height * scale_factor)
resized_img = pil_img.resize((new_width, new_height), Image.LANCZOS)
# 将放大后的图像转换回 numpy 数组
resized_img_np = np.array(resized_img)
# 确保放大后的图像尺寸与原图像尺寸一致,这里简单地进行裁剪
if resized_img_np.shape[0] > img.shape[0] and resized_img_np.shape[1] > img.shape[1]:
start_x = (resized_img_np.shape[0] - img.shape[0]) // 2
start_y = (resized_img_np.shape[1] - img.shape[1]) // 2
resized_img_np = resized_img_np[start_x:start_x + img.shape[0], start_y:start_y + img.shape[1]]
augmented_images.append(resized_img_np)
augmented_labels.append(label)
augmented_images = np.array(augmented_images)
augmented_labels = np.array(augmented_labels)
return augmented_images, augmented_labels
2、进行训练
这个使用的是三层网络结构,数据增强/不增强(注意:如果直接copy这一段就是数据增强后的,不增强的话自己注释就好了),使用的最垃圾的归一化直接除以255
from fuc import *
'''
读取数据
'''
#读取训练集
train_img,train_label=get_data('mstar/mstar/train')
#构建一个标签到整数的映射,然后把标签转换为整数。。因为标签不是传统的数字,所以这么搞
#第一步先对标签进行排序
sorted_label=sorted(set(train_label))
#第二步生成mapping,这样生成对应的他妈的标签就不会是随机的。
label_mapping = {label: idx for idx, label in enumerate(sorted_label)}
train_labels = np.array([label_mapping[label] for label in train_label])
print(f"训练集数量: {len(train_img)}")
#因为是他娘的灰度图像所以就是只有两个维度
height,wid=train_img[0].shape
print(f"训练集图片维度:{wid},{height}")
print(f"训练集标签的样子:{train_labels}")
#读取验证集
val_img,val_label=get_data('mstar/mstar/validation')
val_labels = np.array([label_mapping[label] for label in val_label])
print(f"验证集数量: {len(val_img)}")
height,wid=val_img[0].shape
print(f"验证集维度:{wid},{height}")
print(f"验证集标签的样子:{val_labels}")
# '''
# 这部分进行数据增强,不增强直接注释
# '''
# train_img,train_label=augment_data(train_img,train_label)
# #这里要重新构建mapping,因为增强了数据
# sorted_label=sorted(set(train_label))
# label_mapping = {label: idx for idx, label in enumerate(sorted_label)}
# train_labels = np.array([label_mapping[label] for label in train_label])
# print(f"增强后的训练集数量: {len(train_img)}")
# height,wid=train_img[0].shape
# print(f"增强后的训练集图片维度:{wid},{height}")
# print(f"增强后训练集标签的样子:{train_labels}")
'''
开始准备训练
'''
model=net()
# 数据预处理
# 转换为 PyTorch 张量并调整维度,指定张量的数据类型是32的浮点数
train_images = torch.tensor(train_img, dtype=torch.float32).unsqueeze(1) / 255.0
train_labels = torch.tensor(train_labels, dtype=torch.long)
test_images = torch.tensor(val_img, dtype=torch.float32).unsqueeze(1) / 255.0
test_labels = torch.tensor(val_labels, dtype=torch.long)
# 创建数据集和数据加载器
train_dataset = TensorDataset(train_images, train_labels)
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)
test_dataset = TensorDataset(test_images, test_labels)
test_loader = DataLoader(test_dataset, batch_size=64, shuffle=False)
# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
#optim是pytorch的优化算法模块,model.parameter返回模型中所有需要学习的参数
optimizer = optim.Adam(model.parameters(), lr=0.001)
y_loss=[]#记录损失来画图
'''
训练模型
'''
x_row=[]
y_acc=[]
num_epochs = 30
for epoch in range(num_epochs):
x_row.append(epoch+1)
#把模型调整成训练模式
model.train()
#初始化损失
running_loss = 0.0
#遍历train_loader的每一个批次数据
#注:enumerate是将一个可迭代对象组合为一个带索引的枚举对象,可以同时获得索引和对应的值。在这个项目中就是获取图像和标签
for i, (images, labels) in enumerate(train_loader):
#把优化器中梯度清零,否则梯度会累计
optimizer.zero_grad()
#将数据丢到模型里得到输出
outputs = model(images)
#计算损失,criterion前面定义了,是交叉熵损失
loss = criterion(outputs, labels)
#反向传播
loss.backward()
#根据得到的梯度,使用优化器(前面定义了是Adam)更新模型参数
optimizer.step()
# 这里的loss相当于一个类,用loss.item把loss的值取出来
running_loss += loss.item()
#这个y_loss是一个数组,前面定义了,用于后面的画图
y_loss.append(running_loss / len(train_loader))
#这个函数在前面定义了,用于评测准确率
torch.save(model.state_dict(),'model_training....pth')
print('success saved tempmodel')
y=val_model(test_loader,'model_training....pth')
y_acc.append(y)
print(f'Epoch {epoch + 1}/{num_epochs}, Loss: {running_loss / len(train_loader)}')
torch.save(model.state_dict(),'for_nothing_model.pth')
drawing(x_row,y_loss,'loss_img')
drawing(x_row,y_acc,'acc_img')
未进行数据增强
数据增强后
3、今天新学的BN方法,因为BN方法在求均值和方差不准确所以相当于随机加上了噪声,所以使用BN方法就不用正则化了
from fuc import *
'''
读取数据
'''
#读取训练集
train_img,train_label=get_data('mstar/mstar/train')
#构建一个标签到整数的映射,然后把标签转换为整数。。因为标签不是传统的数字,所以这么搞
#第一步先对标签进行排序
sorted_label=sorted(set(train_label))
#第二步生成mapping,这样生成对应的他妈的标签就不会是随机的。
label_mapping = {label: idx for idx, label in enumerate(sorted_label)}
train_labels = np.array([label_mapping[label] for label in train_label])
print(f"训练集数量: {len(train_img)}")
#因为是他娘的灰度图像所以就是只有两个维度
height,wid=train_img[0].shape
print(f"训练集图片维度:{wid},{height}")
print(f"训练集标签的样子:{train_labels}")
#读取验证集
val_img,val_label=get_data('mstar/mstar/validation')
val_labels = np.array([label_mapping[label] for label in val_label])
print(f"验证集数量: {len(val_img)}")
height,wid=val_img[0].shape
print(f"验证集维度:{wid},{height}")
print(f"验证集标签的样子:{val_labels}")
'''
这部分进行数据增强,不增强直接注释
'''
train_img,train_label=augment_data(train_img,train_label)
#这里要重新构建mapping,因为增强了数据
sorted_label=sorted(set(train_label))
label_mapping = {label: idx for idx, label in enumerate(sorted_label)}
train_labels = np.array([label_mapping[label] for label in train_label])
print(f"增强后的训练集数量: {len(train_img)}")
height,wid=train_img[0].shape
print(f"增强后的训练集图片维度:{wid},{height}")
print(f"增强后训练集标签的样子:{train_labels}")
'''
开始准备训练
'''
model=BN()
# 数据预处理
# 转换为 PyTorch 张量并调整维度,指定张量的数据类型是32的浮点数
train_images = torch.tensor(train_img, dtype=torch.float32).unsqueeze(1) / 255.0
train_labels = torch.tensor(train_labels, dtype=torch.long)
test_images = torch.tensor(val_img, dtype=torch.float32).unsqueeze(1) / 255.0
test_labels = torch.tensor(val_labels, dtype=torch.long)
# 创建数据集和数据加载器
train_dataset = TensorDataset(train_images, train_labels)
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)
test_dataset = TensorDataset(test_images, test_labels)
test_loader = DataLoader(test_dataset, batch_size=64, shuffle=False)
# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
#optim是pytorch的优化算法模块,model.parameter返回模型中所有需要学习的参数
optimizer = optim.Adam(model.parameters(), lr=0.001)
y_loss=[]#记录损失来画图
'''
训练模型
'''
x_row=[]
y_acc=[]
num_epochs = 30
for epoch in range(num_epochs):
x_row.append(epoch+1)
#把模型调整成训练模式
model.train()
#初始化损失
running_loss = 0.0
#遍历train_loader的每一个批次数据
#注:enumerate是将一个可迭代对象组合为一个带索引的枚举对象,可以同时获得索引和对应的值。在这个项目中就是获取图像和标签
for i, (images, labels) in enumerate(train_loader):
#把优化器中梯度清零,否则梯度会累计
optimizer.zero_grad()
#将数据丢到模型里得到输出
outputs = model(images)
#计算损失,criterion前面定义了,是交叉熵损失
loss = criterion(outputs, labels)
#反向传播
loss.backward()
#根据得到的梯度,使用优化器(前面定义了是Adam)更新模型参数
optimizer.step()
# 这里的loss相当于一个类,用loss.item把loss的值取出来
running_loss += loss.item()
#这个y_loss是一个数组,前面定义了,用于后面的画图
y_loss.append(running_loss / len(train_loader))
#这个函数在前面定义了,用于评测准确率
torch.save(model.state_dict(),'model_training....pth')
print('success saved tempmodel')
y=valBN_model(test_loader,'model_training....pth')
y_acc.append(y)
print(f'Epoch {epoch + 1}/{num_epochs}, Loss: {running_loss / len(train_loader)}')
torch.save(model.state_dict(),'BN_augment_model.pth')
drawing(x_row,y_loss,'loss_img')
drawing(x_row,y_acc,'acc_img')
BN方法加上数据增强
from fuc import *
'''
读取数据
'''
#读取训练集
train_img,train_label=get_data('mstar/mstar/train')
#构建一个标签到整数的映射,然后把标签转换为整数。。因为标签不是传统的数字,所以这么搞
#第一步先对标签进行排序
sorted_label=sorted(set(train_label))
#第二步生成mapping,这样生成对应的他妈的标签就不会是随机的。
label_mapping = {label: idx for idx, label in enumerate(sorted_label)}
train_labels = np.array([label_mapping[label] for label in train_label])
print(f"训练集数量: {len(train_img)}")
#因为是他娘的灰度图像所以就是只有两个维度
height,wid=train_img[0].shape
print(f"训练集图片维度:{wid},{height}")
print(f"训练集标签的样子:{train_labels}")
#读取验证集
val_img,val_label=get_data('mstar/mstar/validation')
val_labels = np.array([label_mapping[label] for label in val_label])
print(f"验证集数量: {len(val_img)}")
height,wid=val_img[0].shape
print(f"验证集维度:{wid},{height}")
print(f"验证集标签的样子:{val_labels}")
'''
这部分进行数据增强,不增强直接注释
'''
train_img,train_label=augment_data(train_img,train_label)
#这里要重新构建mapping,因为增强了数据
sorted_label=sorted(set(train_label))
label_mapping = {label: idx for idx, label in enumerate(sorted_label)}
train_labels = np.array([label_mapping[label] for label in train_label])
print(f"增强后的训练集数量: {len(train_img)}")
height,wid=train_img[0].shape
print(f"增强后的训练集图片维度:{wid},{height}")
print(f"增强后训练集标签的样子:{train_labels}")
'''
开始准备训练
'''
model=deeped_BN()
# 数据预处理
# 转换为 PyTorch 张量并调整维度,指定张量的数据类型是32的浮点数
train_images = torch.tensor(train_img, dtype=torch.float32).unsqueeze(1) / 255.0
train_labels = torch.tensor(train_labels, dtype=torch.long)
test_images = torch.tensor(val_img, dtype=torch.float32).unsqueeze(1) / 255.0
test_labels = torch.tensor(val_labels, dtype=torch.long)
# 创建数据集和数据加载器
train_dataset = TensorDataset(train_images, train_labels)
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)
test_dataset = TensorDataset(test_images, test_labels)
test_loader = DataLoader(test_dataset, batch_size=64, shuffle=False)
# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
#optim是pytorch的优化算法模块,model.parameter返回模型中所有需要学习的参数
optimizer = optim.Adam(model.parameters(), lr=0.001)
y_loss=[]#记录损失来画图
'''
训练模型
'''
x_row=[]
y_acc=[]
num_epochs = 30
for epoch in range(num_epochs):
x_row.append(epoch+1)
#把模型调整成训练模式
model.train()
#初始化损失
running_loss = 0.0
#遍历train_loader的每一个批次数据
#注:enumerate是将一个可迭代对象组合为一个带索引的枚举对象,可以同时获得索引和对应的值。在这个项目中就是获取图像和标签
for i, (images, labels) in enumerate(train_loader):
#把优化器中梯度清零,否则梯度会累计
optimizer.zero_grad()
#将数据丢到模型里得到输出
outputs = model(images)
#计算损失,criterion前面定义了,是交叉熵损失
loss = criterion(outputs, labels)
#反向传播
loss.backward()
#根据得到的梯度,使用优化器(前面定义了是Adam)更新模型参数
optimizer.step()
# 这里的loss相当于一个类,用loss.item把loss的值取出来
running_loss += loss.item()
#这个y_loss是一个数组,前面定义了,用于后面的画图
y_loss.append(running_loss / len(train_loader))
#这个函数在前面定义了,用于评测准确率
torch.save(model.state_dict(),'model_training....pth')
print('success saved tempmodel')
y=val_deep_BN_model(test_loader,'model_training....pth')
if epoch>10 and y>y_acc[epoch-1] :
#今天问过老师了,损失是用于训练过程中对训练进行诊断的,判断代码有没有写错。同时由于BN会随机给数据增加噪声,所以可以保存最好的模型
torch.save(model.state_dict(), 'best_10deeped_BN_augment_model.pth')
y_acc.append(y)
print(f'Epoch {epoch + 1}/{num_epochs}, Loss: {running_loss / len(train_loader)}')
torch.save(model.state_dict(),'deeped_BN_augment_model.pth')
drawing(x_row,y_loss,'loss_img')
drawing(x_row,y_acc,'acc_img')
加深后的
4、超级加深,变成十层
from fuc import *
'''
读取数据
'''
#读取训练集
train_img,train_label=get_data('mstar/mstar/train')
#构建一个标签到整数的映射,然后把标签转换为整数。。因为标签不是传统的数字,所以这么搞
#第一步先对标签进行排序
sorted_label=sorted(set(train_label))
#第二步生成mapping,这样生成对应的他妈的标签就不会是随机的。
label_mapping = {label: idx for idx, label in enumerate(sorted_label)}
train_labels = np.array([label_mapping[label] for label in train_label])
print(f"训练集数量: {len(train_img)}")
#因为是他娘的灰度图像所以就是只有两个维度
height,wid=train_img[0].shape
print(f"训练集图片维度:{wid},{height}")
print(f"训练集标签的样子:{train_labels}")
#读取验证集
val_img,val_label=get_data('mstar/mstar/validation')
val_labels = np.array([label_mapping[label] for label in val_label])
print(f"验证集数量: {len(val_img)}")
height,wid=val_img[0].shape
print(f"验证集维度:{wid},{height}")
print(f"验证集标签的样子:{val_labels}")
'''
这部分进行数据增强,不增强直接注释
'''
train_img,train_label=augment_data(train_img,train_label)
#这里要重新构建mapping,因为增强了数据
sorted_label=sorted(set(train_label))
label_mapping = {label: idx for idx, label in enumerate(sorted_label)}
train_labels = np.array([label_mapping[label] for label in train_label])
print(f"增强后的训练集数量: {len(train_img)}")
height,wid=train_img[0].shape
print(f"增强后的训练集图片维度:{wid},{height}")
print(f"增强后训练集标签的样子:{train_labels}")
'''
开始准备训练
'''
model=deeped_BN()
# 数据预处理
# 转换为 PyTorch 张量并调整维度,指定张量的数据类型是32的浮点数
train_images = torch.tensor(train_img, dtype=torch.float32).unsqueeze(1) / 255.0
train_labels = torch.tensor(train_labels, dtype=torch.long)
test_images = torch.tensor(val_img, dtype=torch.float32).unsqueeze(1) / 255.0
test_labels = torch.tensor(val_labels, dtype=torch.long)
# 创建数据集和数据加载器
train_dataset = TensorDataset(train_images, train_labels)
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)
test_dataset = TensorDataset(test_images, test_labels)
test_loader = DataLoader(test_dataset, batch_size=64, shuffle=False)
# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
#optim是pytorch的优化算法模块,model.parameter返回模型中所有需要学习的参数
optimizer = optim.Adam(model.parameters(), lr=0.001)
y_loss=[]#记录损失来画图
'''
训练模型
'''
x_row=[]
y_acc=[]
num_epochs = 30
for epoch in range(num_epochs):
x_row.append(epoch+1)
#把模型调整成训练模式
model.train()
#初始化损失
running_loss = 0.0
#遍历train_loader的每一个批次数据
#注:enumerate是将一个可迭代对象组合为一个带索引的枚举对象,可以同时获得索引和对应的值。在这个项目中就是获取图像和标签
for i, (images, labels) in enumerate(train_loader):
#把优化器中梯度清零,否则梯度会累计
optimizer.zero_grad()
#将数据丢到模型里得到输出
outputs = model(images)
#计算损失,criterion前面定义了,是交叉熵损失
loss = criterion(outputs, labels)
#反向传播
loss.backward()
#根据得到的梯度,使用优化器(前面定义了是Adam)更新模型参数
optimizer.step()
# 这里的loss相当于一个类,用loss.item把loss的值取出来
running_loss += loss.item()
#这个y_loss是一个数组,前面定义了,用于后面的画图
y_loss.append(running_loss / len(train_loader))
#这个函数在前面定义了,用于评测准确率
torch.save(model.state_dict(),'model_training....pth')
print('success saved tempmodel')
y=val_deep_BN_model(test_loader,'model_training....pth')
if epoch>10 and y>y_acc[epoch-1] :
#今天问过老师了,损失是用于训练过程中对训练进行诊断的,判断代码有没有写错。同时由于BN会随机给数据增加噪声,所以可以保存最好的模型
torch.save(model.state_dict(), 'best_10deeped_BN_augment_model.pth')
y_acc.append(y)
print(f'Epoch {epoch + 1}/{num_epochs}, Loss: {running_loss / len(train_loader)}')
torch.save(model.state_dict(),'deeped_BN_augment_model.pth')
drawing(x_row,y_loss,'loss_img')
drawing(x_row,y_acc,'acc_img')
发现结果并没有变得很好。这个应该是没有过拟合风险的,因为损失其实比五层高,
5、把所有的结果集合一下吧(兄弟们可以不用写这个,写这个只是展示结果)
import torch
import torch.nn as nn
import numpy as np
from fuc import get_data
from torch.utils.data import TensorDataset, DataLoader
from fuc import net,BN,deeped_BN,val_model,valBN_model,val_deep_BN_model,val_tendeep_BN_model,ten_deeped_BN
'''
获取数据
'''
val_img,val_label=get_data('mstar/mstar/validation')
sorted_label=sorted(set(val_label))
#标签对应
label_mapping = {label: idx for idx, label in enumerate(sorted_label)}
train_labels = np.array([label_mapping[label] for label in val_label])
val_labels = np.array([label_mapping[label] for label in val_label])
#验证一下该死的标签有没有对应上
print(f"验证集数量: {len(val_img)}")
height,wid=val_img[0].shape
print(f"验证集维度:{wid},{height}")
print(f"验证集标签的样子:{val_labels}")
test_images = torch.tensor(val_img, dtype=torch.float32).unsqueeze(1) / 255.0
test_labels = torch.tensor(val_labels, dtype=torch.long)
test_dataset = TensorDataset(test_images, test_labels)
test_loader = DataLoader(test_dataset, batch_size=64, shuffle=False)
#/255归一化,未数据增强,三层网络
model=net()
print("#/255归一化,未数据增强,三层网络")
y=val_model(test_loader,'for_nothing_model.pth')
#/255归一化,数据增强,三层网络
print("#/255归一化,数据增强,三层网络")
y=val_model(test_loader,'augumented_data_model.pth')
#BN方法,数据增强,三层网络
model=BN()
print("#BN方法,数据增强,三层网络")
y=valBN_model(test_loader,'BN_augment_model.pth')
#BN方法,数据增强,5层网络
model=deeped_BN()
print('#BN方法,数据增强,5层网络')
y=val_deep_BN_model(test_loader,'best_deeped_BN_augment_model.pth')
#十层网络。前两层BN
model=ten_deeped_BN()
print('十层网络。前两层BN')
y=val_tendeep_BN_model(test_loader,'best_10deeped_BN_augment_model.pth')
这个就是结果了,最好就到98%,孩子想不出办法了。