import torch
import torch.nn.functional as F
import numpy as np
import matplotlib.pyplot as plt
xy = np.loadtxt('diabetes.csv.gz', delimiter=',', dtype=np.float32)
x_data = torch.from_numpy(xy[:, :-1])
y_data = torch.from_numpy(xy[:, [-1]])
loss_list = []
epoch_list = np.arange(1000)
acc_list = []
class Model(torch.nn.Module):
"""
LinearModel该类继承自torch.nn.Module,Module类中有多种方法可用
LinearModel该类必须实现两个方法,一个是__init__另一个是forward
__init__即该类的构造行数,初始化对象时默认调用
forward是来实现前馈时所要进行的计算,
而关于反馈计算,Module构造的对象会根据计算图(Module会构建计算图)自动进行反馈计算
也可自己定义反馈求导,对于pytorch支持的计算,可以自己定义类,而对于pytorch不支持的也可继承Functions类来实现
模型继承:linear模型
linear(1, 1)是特征和输出的维度为一维
forward:构建模型中的各个层的关系---也是输出怎么到输出的,用到哪些层;---可以调用__init__里的函数
__init__:通多调用nn.Module中函数进行搭建每一层所用到的函数,函数的参数
forward:将__init__中的搭建好的函数连通起来,告诉我们怎么连通,叙述整个流程
"""
def __init__(self):#重写父类的构造函数
super(Model, self).__init__()#同时继承父类的构造函数
self.linear1 = torch.nn.Linear(8,6)#输入维度和输出维度,即W的矩阵
self.linear2 = torch.nn.Linear(6,4)
self.linear3 = torch.nn.Linear(4,1)
self.activate1 = torch.nn.ReLU()
self.activate2 = torch.nn.Sigmoid()
# 通过torch中的Linear类构造一个对象(类加括号是在构造对象),该Linear包含权重w和偏执b这两个tensor,
# 自动进行wx+b的运算,而且Linear也是继承自Module,因此也会自动进行反向传播
def forward(self, x):
# 重写Model中forward函数,同时在Model类中的__call__函数中调用forward函数
# 也就是说可以通过Model的实例直接传参到该函数(callable)
#y_pred = F.sigmoid(self.linear(x))
# x = self.sigmoid(self.linear1(x))
# x = self.sigmoid(self.linear2(x))
x = self.activate1(self.linear1(x))
x = self.activate1(self.linear2(x))
x = self.activate2(self.linear3(x))
#linear也是构造于Model,也是callable的
return x
"""
模型的实例化
调用损失函数--criterion
选择优化器,学习率设置为0.01;同时其他的值通过model.parameters()函数进行初始化。
里面自己有各种参数,权重 偏置
"""
model = Model()
criterion = torch.nn.BCELoss(reduction='mean')
#损失函数,第一个值表示是否要求均值,第二个值表示是否需要求和来降维,criterion需要yheat和y
optimizer = torch.optim.SGD(model.parameters(), lr=0.1)
#优化器,注意不是来自Model类,所以不会生成计算图,这是给SGD这个类进行实例化,
# 第一个参数params,在这里传入的是model的一个函数model.parameters(),
# 该方法会检查model中的所有成员,通过调用了linear.parameters()方法,获得所有权重,
# 会将需要优化的权重都加到需要训练的参数集合上
#lr即学习率
for epoch in range(1000):
y_pred = model(x_data)
#模型传入特征值--返回预测值y_pred
loss = criterion(y_pred, y_data)
loss_list.append(loss.item())
# 往损失函数-criterion-中传入预测值和真实值--返回损失值loss
print(epoch, loss.item())
#输出当前迭代次数 + 当前损失值
optimizer.zero_grad()
#通过zero_grad函数将之前的梯度值(即损失函数的导数)设置为0
loss.backward()
# .backward进行反向传播
optimizer.step()
#optimizer.step(),通过前面算出的梯度和学习率进行w和偏置b的迭代更新
y_pred_label = torch.where(y_pred >= 0.5, torch.tensor([1.0]), torch.tensor([0.0]))
# torch.where()
# 函数的作用是按照一定的规则合并两个tensor类型。
# torch.where(condition,a,b)其中
# 输入参数condition:条件限制,如果满足条件,则选择a,否则选择b作为输出。
# 注意:a和b是tensor.
accuracy = torch.eq(y_pred_label, y_data).sum().item() / y_data.size(0)
acc_list.append(accuracy)
# torch.eq()函数就是用来比较对应位置数字,相同则为1,否则为0,输出与那两个tensor大小相同,并且其中只有1和0。
#
# a = [0 1 2 3 4]
# b = [4 3 2 1 4]
# torch.eq()
# 得[0 0 1 0 1]
#
# torch.eq().sum()
# 就是将所有值相加,但得到的仍是tensor.
# torch.eq().sum()
# 得到的结果就是[2]。
# torch.eq().sum().item()
# 得到值2。
# 用这个来计算训练集、验证集准确率时,记得一个epoch后要除的分母是训练集、验证集的数据量大小
print("loss = ", loss.item(), "acc = ", accuracy)
"""
输出最后的权值w
输出最后的偏置b
设置测试集数据
将测试集放入模型中进行预测
通过.data 输出预测数据
"""
# print('w = ', model.linear.weight.item())
# print('b = ', model.linear.bias.item())
#
# x_test = torch.Tensor([[4.0]])
# y_test = model(x_test)
# print('y_pred = ', y_test.data)
# x = np.linspace(0,10,200)
# x_t = torch.Tensor(x).view((200,1))
# y_t = model(x_t)
# y = y_t.data.numpy()
plt.plot(epoch_list,loss_list)
plt.plot(epoch_list,acc_list)
# plt.plot([0,10],[0.5,0.5],c='r')
# plt.xlabel('Hours')
# plt.ylabel('Prob of pass')
# plt.grid()
plt.show()