• 搭建全连接网络进行分类(糖尿病为例)


    拿来练手,大神请绕道。

    1.网上的代码大多都写在一个函数里,但是其实很多好论文都是把网络,数据训练等分开写的。

    2.分开写就是有一个需要注意的事情,就是要import 要用到的文件中的模型或者变量等。

    3.全连接的回归也写了,有空再上传吧。

    4.一般都是先写data或者model

    1. import torch
    2. import torch.nn as nn
    3. import torch.nn.functional as F
    4. #nn.func这个里面很多功能其实nn里就有,可以不导入,而且后面新的版本的torch也取消了cc.functional里面的部分函数
    5. #定义网络,需要定义两部分,一部分就是初始化,另一部分就是数据流
    6. class FCNet(nn.Module):
    7. def __init__(self):
    8. super(FCNet,self).__init__()
    9. self.fc1 = nn.Linear(8,16
    10. #初始的这个8,要和你的数据的特征数一样才行,后面的数可以随意设置,但是不要太多,容易过拟合
    11. # self.fc2 = nn.Linear(50,20)
    12. self.fc3 = nn.Linear(16,2)#二分类,输出2,其实1也可以的
    13. #最后的就是分类数,因为用的sigmod和交叉熵损失,就不用额外加softmax了,多分类要用softmax
    14. self.sig = nn.Sigmoid()
    15. # self.drop = nn.Dropout(0.3)
    16. #可以把用到的放在这里,也可以用nn.Sequential()放在一起,这样后面的话就可以直接用这个,不用写那么多了
    17. def forward(self,x):
    18. x = self.sig(self.fc1(x))
    19. # x = self.sig(self.fc2(x))
    20. x = self.sig(self.fc3(x))
    21. return x
    22. #就是x要怎么在网络中走,要写一遍
    23. #可以自己输出测试一下看看网络是不是自己想的那样,在真的调用的时候再屏蔽掉
    24. # net= FCNet()
    25. # print(net)

    首先看看数据是是啥样,outcome就是有没有糖尿病

    其实可以手动把csv分成train和test

    1. import pandas as pd
    2. from sklearn.model_selection import train_test_split
    3. import torch
    4. from torch.utils.data import Dataset
    5. from torch.utils.data import DataLoader
    6. import numpy as np
    7. #导入pands是为了读数据,当然使用numpy也可以读得,sklearn是为了把训练数据分为训练和验证集
    8. data = pd.read_csv('./train.csv')
    9. #就是把对应的数据哪出来,x代表的是feature上的data,y代表的是label,因为pd可以读到最上面的标签,所以从第2行(i=1)开始读就行
    10. x = data.iloc[1:,:-1]
    11. y = data.iloc[1:,[-1]]
    12. #可以输出看看数据对不对,x中不应该包含labels
    13. # print(x)
    14. # print(y)
    15. #test_size就是划分的比例,后面的是种子,意思是每次运行这个函数时候,0.8就是那些,0.2也还是每次一样,如果想要不一样,只要每次运行这个函数时候换个值就行
    16. x_train,x_test,y_train,y_test = train_test_split(x,y,test_size=0.2,random_state=0)
    17. #print(x_train,y_test)
    18. # print(x_test,y_test)
    19. #给数据进行归一化,可以用很多方法,我用最简单的归一到-1到1
    20. x_train = x_train.apply(lambda x: (x - x.mean()) / (x.std()))
    21. x_test = x_test.apply(lambda x: (x - x.mean()) / (x.std()))
    22. #写dataset可以用两种方法,第一种就是 每一个数据自己单独处理,第二个就是要自己重写dataset类
    23. #1.
    24. # 可以使用分别的处理,把数据(首先转换为tensor,或者把dataframe.valus拿出来才能转换为tensor)转换为tensor并且数据类型转换为float32,如果测试没有真值,需要单独转换
    25. # x_train = torch.tensor(np.array(x_train),dtype=torch.float32)
    26. # y_train = torch.tensor(np.array(y_train),dtype=torch.float32)
    27. # x_test = torch.tensor(np.array(x_test),dtype=torch.float32)
    28. # y_test = torch.tensor(np.array(x_test),dtype=torch.float32)
    29. # train_dataset = torch.utils.data.TensorDataset(x_train,y_train)
    30. # test_dataset = torch.utils.data.TensorDataset(x_test,y_test)
    31. #2.也可以直接重写dataset
    32. class dataset(Dataset):
    33. def __init__(self, x, y):
    34. #把值拿出来或者变为np类型才能转换为tensor
    35. # self.data = torch.tensor(x.values,dtype=torch.float32)
    36. # self.labels = torch.tensor(y.values,dtype=torch.float32)
    37. self.data = torch.tensor(np.array(x),dtype=torch.float32)
    38. self.labels = torch.tensor(np.array(y),dtype=torch.float32)
    39. def __len__(self):
    40. return len(self.data)
    41. def __getitem__(self,idx):
    42. return self.data[idx],self.labels[idx]
    43. #应该返回的是list类型,不是字典也不是set
    44. BATCH_SIZE = 64
    45. #验证集一般不用shuffle
    46. train_dataset = dataset(x_train,y_train)
    47. test_dataset = dataset(x_test,y_test)
    48. # print(train_dataset)
    49. train_loader = DataLoader(train_dataset,batch_size=BATCH_SIZE,shuffle=True)
    50. test_lodaer = DataLoader(test_dataset,batch_size=BATCH_SIZE,shuffle=False)
    51. # print(train_loader)

    然后就可以写train或者test了,其实test和train一样

    1. from Model import FCNet
    2. import torch
    3. import torch.nn as nn
    4. import torch.optim as optim
    5. import matplotlib.pyplot as plt
    6. import data
    7. #导入要调用的net和data,也可以from data import xxx 这样可以直接用xxx,现在的这个需要用data.xxx
    8. #看自己的设备,最好用gpu来跑
    9. if (torch.cuda.is_available()):
    10. my_device = torch.device('cuda')
    11. else:
    12. my_device = torch.device('cpu')
    13. print(my_device)
    14. #实例化一个net,并且放到gpu上,需要放到gpu上的有inputs,labels,net,loss
    15. net = FCNet().to(my_device)
    16. # print(net)
    17. #定义损失函数和优化器
    18. criterion = nn.CrossEntropyLoss()
    19. #一开始是不需要weight_decay(也就是l2正则化),可以等出现过拟合在用,也可以先用上
    20. optimizer = optim.Adam(net.parameters(),lr=0.001,weight_decay=0.01)
    21. epochs = 600
    22. #定义train,因为一边训练一边验证,所有就把两个loader都放进去了,不过写法很多,也可以不放dataloader,放epoches也可以
    23. def train(dataloader,valloader):
    24. losses = []
    25. acces = []
    26. losses_val = []
    27. for epoch in range(epochs):
    28. loss_batch = 0
    29. for i,data in enumerate(dataloader):
    30. #需要注意的,这里的inputs和labels和之前定义的dataset相关,需要是list类型才可以
    31. inputs,labels = data
    32. #print(data)可以打印出来查看一下
    33. inputs,labels = inputs.to(my_device),labels.to(my_device)
    34. optimizer.zero_grad()#每次要梯度清零
    35. outputs = net(inputs)
    36. #print(outputs)
    37. #model的最后一层是sigmod
    38. #labels的格式需要注意,因为现在是[[1],[0],[1],[1]..]这样得格式,无法放到交叉熵了,需要时[0,1,1,1...]这样得格式才行
    39. loss = criterion(outputs,labels.squeeze(1).long()).to(my_device)
    40. #print(labels.squeeze(1).long())
    41. loss.backward()
    42. optimizer.step()
    43. loss_batch += loss.item()
    44. length = i
    45. #验证的时候不用反向传播和梯度下降这些
    46. net.eval()
    47. count = 0
    48. right = 0
    49. loss_batch_val =0
    50. with torch.no_grad():
    51. for j,data2 in enumerate(valloader):
    52. val_inputs,val_labels = data2
    53. val_inputs,val_labels = val_inputs.to(my_device),val_labels.squeeze(1).long().to(my_device)
    54. val_outputs = net(val_inputs)
    55. loss_val = criterion(val_outputs,val_labels)
    56. #因为net的最后一层是2,所以输出的是2维的【0.6,0.4】这种,但是这个可以直接放到交叉熵中
    57. #——中放的是概率,pred中放的是预测的类别,算损失还是要用outputs,但是算准确率就是用pred和真实labels相比了
    58. _,pred = torch.max(val_outputs,1)
    59. #print(pred)
    60. right = (pred == val_labels).sum().item()
    61. count = len(val_labels)
    62. acc = right/count
    63. loss_batch_val += loss_val.item()
    64. length2 = j
    65. if epoch % 10 == 9:
    66. print('train_epoch:',epoch+1,'train_loss:',loss_batch/length,'val_loss:',loss_batch_val/length2,'acc:',acc)
    67. losses.append(loss_batch/length)
    68. acces.append(acc)
    69. losses_val.append(loss_batch_val/length2)
    70. #可以画一些曲线,输出一些值
    71. plt.plot(range(60),losses,color ='blue',label ='train_loss')
    72. plt.plot(range(60),acces, color ='red',label ='val_acc')
    73. plt.plot(range(60),losses_val,color ='yellow',label ='val_loss')
    74. plt.legend()
    75. plt.show()
    76. torch.save(net.state_dict(),'./weights_epoch1000.pth')
    77. #保存参数
    78. train(data.train_loader,data.test_lodaer)

    最后看一下结果,最后的准确率在85%左右,还可以,毕竟数据不多,也是简单的全连接。

    在这个结果之前出现了很多问题,比如波动很大,损失先降后升等问题,找个有问题的图

    下面是一些总结:

    1.跳跃很大,波动:增大batch_size,减小lr。

    2.降低过拟合

            a.降低模型的复杂程度,但是修改具体的神经元个数,因为这个网络本身就不大,所有没啥用,模型非常大没准会有用。

            b.batchsize增大,lr减小是有效的。

            c.输入数据进行归一化是有用的,归一化之后lr可以调大一点,收敛变快了。

            d.L2正则化是有用的,很有用。dropout应该也有用,但是模型本来就很小,我试了试没啥差别。而且有正则化之后可以加速收敛,lr可以稍微调大一点,较少的epoches也可以收敛了,而已acc也会更高一点,稳定一点。

  • 相关阅读:
    session.createDataFrame(personRdd, Person.class) 返回的dataframe没有数据问题
    城市合伙人招募令!
    内裤洗衣机有用吗?公认好用的四大款内衣洗衣机推荐
    牛客小白月赛#55
    黑客首选攻击语言为什么是Python?你知道吗?
    阿里云关系型数据库有哪些?RDS云数据库汇总
    MobPush丨Android端SDK API
    【自动化测试】——robotframework实战(二)新建测试用例
    【clickhouse专栏】clickhouse性能为何如此卓越
    由ASP.NET Core根据路径下载文件异常引发的探究
  • 原文地址:https://blog.csdn.net/wacebb/article/details/133469364