前言:最近忙于做作业,平常看资料之类的都觉得没困难,一到动手就歇菜。用来记录生活。
整个题目的要求呢:第一是构建一个能识别手写体的神经网络,输入64维的数据,然后输出10个数据。
个人理解呢,就是这个数据集是,8*8的就是64维度。10个输出,就是0-9数字判断。
import torch
from matplotlib import pyplot as plt
from torch import nn, optim
from torch.nn.modules import dropout
from torch.utils.data import Dataset, DataLoader, dataset
import torch.nn.functional as F
import time
import numpy as np
from sklearn import datasets
from sklearn.model_selection import train_test_split
import tensorflow as tf
#设置字体为SimHei显示中文
plt.rcParams['font.sans-serif'] = ['SimHei']
#设置正常显示字符
plt.rcParams['axes.unicode_minus'] = False
#时间函数
start = time.time()
#导入数据
digits=datasets.load_digits()
x=digits.data
x=np.array(x,dtype=np.float32)
y=digits.target
'''
数字识别思想:该模型能输出是个标签的概率,对应真是标签的概率输出尽可能到1.则其他标签概率尽可能为0
则所有位置对应概率和为1
与此对应,真是标签值可以转化为一个10维的one-hot向量,在与真实值对应的位置上,为1,其他值用0填充
'''
#生成一个用zeros填充的数组,一共有y行,10列,类型是float32
z=np.zeros([len(y),10],dtype=np.float32)
#对Z重新构建
for i in range(len(y)):
a=int(y[i])
z[i][a]=1
# print(z)
x_train,x_test,z_train,z_test=train_test_split(x,z,random_state=4,test_size=0.2)
print('数组数据大小',x_train.shape)
class FD(Dataset):
def __init__(self,x_train,y_train):
self.x = x_train
self.y = y_train
def __len__(self):
return len(self.x)
def __getitem__(self, idx):
return self.x[idx],self.y[idx]
datasets_train = FD(x_train,z_train)
datasets_test = FD(x_test,z_test)
print('-'*100)
# for i in range(len(datasets)):
# print(datasets[i])
# print(len(datasets))
#创建网络层
class Net(nn.Module):
#初始化函数
def __init__(self,in_features=64,out_features=10,dropout=0.1):
super(Net, self).__init__()
#通过全连接降低维度。有一个输入,两个隐藏层(第一个有192个神经元,第二个有80个神经元)一个输出。
self.fc1 = nn.Linear(in_features, 192)
self.fc2 = nn.Linear(192, 80)
self.fc3 = nn.Linear(80, out_features)
# #设置dropout
self.relu = nn.ReLU()#激活函数
# self.dropout = nn.Dropout(p=dropout) #设置丢弃率
self.batchnorm1 = nn.BatchNorm1d(192) #BN优化
self.batchnorm2 = nn.BatchNorm1d(80) #BN优化
#网络前向层
def forward(self, inputs):
# x = F.relu(self.fc1(x))
# x = F.relu(self.fc2(x))
# x = self.fc3(x)
x = self.relu(self.fc1(inputs))
x = self.batchnorm1(x)
x = self.relu(self.fc2(x))
x = self.batchnorm2(x)
# x = self.relu(self.fc3(x))
# x = self.dropout(x)
# x = self.layer_out(x)
return x
def Acc(output,target):
n=0
a=len(output)
for k in range(a):
M1= int(output[k].argmax())
M2= int(target[k].argmax())
if M1 == M2:
n+= 1
return n
# def Xavier_Initialization(self):
# # 默认方法
# for m in self.modules():
# if isinstance(m, (nn.Conv2d, nn.Linear)):
# nn.init.xavier_uniform_(m.weight)
net = Net()
DL = DataLoader(dataset=datasets_train, batch_size=200, shuffle=True)
optimizer = optim.SGD(net.parameters(), lr=0.001)
# optimizer = optim.Adam(net.parameters(), lr=0.01)
criterion = nn.CrossEntropyLoss()
# criterion = nn.MSELoss()
def train(DL):
b=0
c=0
for epoch in range(100):
for i_batch, sample_batched in enumerate(DL):
input=sample_batched[0]
target=sample_batched[1]
output = net(input)
optimizer.zero_grad() # zero the gradient buffers
loss = criterion(output, target)
loss.backward()
optimizer.step()
b += Acc(output, target)
c += len(input)
print("训练准确率:", b / c, "loss:", loss)
# print(input)
# print(output)
# print("i_batch:",i_batch,"loss:",loss,'accuracy:')
# print('*'*50)
# print('第',epoch,'轮')
return b/c
#预测
acc=[]
epoch=[]
for i in range(5):
d=train(DL)
acc.append(d)
epoch.append(i)
plt.plot(epoch, acc)
plt.title('准确率')
plt.show()
with torch.no_grad(): # 不再进行梯度计算
DL1=DataLoader(dataset=datasets_test,batch_size=100)
b=0
c=0
for i_batch, sample_batched in enumerate(DL1): # 讲input和target提取出来
input = sample_batched[0]
target1 = sample_batched[1]
out = net(input) # 预测函数
b+=Acc(out,target1)
c+=len(input)
print("预测准确率:",b/c)
end = time.time()
print("时间",(end-start),'s')