从实现角度整理神经网络框架及其他要点
torch网络框架
读取文件
数据预处理
构造数据加载类
# 1. Dataset
# 定义获取数据集的类。继承基类Dataset,自定义数据集及对应标签
class mydataset(Dataset):
# 读取加载数据
def __init__(self,data_x,data_y_source): # data_x是训练数据,data_y_source是标签,数据类型是nd.array(创建的时候是list,转成的array),数据要对齐,
self._x=data_x
self._y=data_y_source
self._len=data_y_source.shape[0]
def __getitem__(self,item):
return self._x[item],self._y[item]
def __len__(self):# 返回整个数据的长度
return self._len
# 获取数据,集中数据
data_dataset=mydataset(data_x,data_y_source)
print(data_dataset[2]) # 相当于调用__getitem__(2)
print(data_dataset.__len__())
# 以上数据以tuple返回,每次只返回一个样本,实际上,Dataset只负责数据的抽取
# 如果希望批量处理batch,同时进行shuffle和并行加速等操作,可选择DataLoader。
# 可以实例化一个dataset,然后用Dataloader 包起来
data_set_loader = DataLoader(data_dataset, batch_size=4,shuffle=True)
# 2. DataLoader
# DataLoader的格式:[https://blog.csdn.net/wuyanne/article/details/120768148](https://blog.csdn.net/wuyanne/article/details/120768148)
# 实现
data_loader = data.DataLoader(data,batch_size=2,shuffle=False,num_workers=2)
# 读取
for i, traindata in enumerate(test_loader):
print('i:', i)
Data,Label = traindata
print('Data:',Data)
print('Label:',Label)
# 迭代
# 可以像使用迭代器一样使用它,比如进行循环操作,可以通过iter命令将其转换为迭代器
dataiter = iter(data_loader)
划分数据集
# 1 数据加载类划分
# 划分 训练集 测试集, 随机混乱顺序划分的 四舍五入
train_data,test_data=random_split(data_dataset,[round(0.8*data_dataset._len),round(0.2*data_dataset._len)])#这个参数有的版本没有 generator=torch.Generator().manual_seed(0)
# 2
train_test_split
搭建模型
__init__函数和forward函数必须要有,class函数自动执行这两个函数,__init__函数中要定义整个网络中的所有网络层,前馈函数里要根据整个网络把__init__函数中定义的网络层连起来。
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
class Net(nn.Module):
def __init__(self):
...
def forward(self,x):
...
def ...
搭建网络
定义所有要用到的网络层
比喻:制作积木块
- 要注意维度问题,目前我是根据报错调试程序,程序说它需要什么类型的数据我就给他什么类型的数据
def __init__(self):
#使用super()方法调用基类的构造器,即nn.Module.__init__(self)
super(CNN,self).__init__()
# 1 input image channel ,6 output channels,5x5 square convolution kernel
self.conv1=nn.Conv1d(500,12,2)
# 6 input channl,16 output channels,5x5 square convolution kernel
self.conv2=nn.Conv1d(6,16,4)
# an affine operation:y=Wx+b
self.fc1=nn.Linear(32,16)
self.fc2=nn.Linear(16,8)
self.fc3=nn.Linear(8,1)
self.pool = nn.MaxPool2d(2, 2)
self.Sigmoid = nn.Sigmoid ()
前馈函数
将__init__函数中定义的各个网络层输入输出衔接起来
比喻:把积木块搭起来,用线串起来
- 网络的输入x,通常数据类型为张量,如果要用cuda并行,记得把x放入gpu
- 全连接层可以和激活函数写在一起,代码简洁并且不会忘写激活函数
def forward(self,x):
# x是网络的输入,然后将x前向传播,最后得到输出
x=torch.Tensor(x).to(device)
x=x.unsqueeze(0) # 输入,根据需要判断是否需要多加维度,比如LSTM、CNN需要三维数据,二维数据进来要多加一个维度
x=self.Sigmoid(self.conv1(x)) # 一个一维卷积层,一个sigmoid层
x=self.pool(x) # 定义了2x2的池化层
x=self.Sigmoid(self.conv2(x))
x=x.view(-1,self.num_flat_features(x)) 将x拉伸成一维张量,进行
x=self.Sigmoid(self.fc1(x))
x=self.Sigmoid(self.fc2(x))
x=self.fc3(x)
return x[0]
# 根据需要,自己定义的方法。
# 计算张量中共有多少个有效数据,计算数量,便于拉伸成一维张量
def num_flat_features(self,x):
size=x.size()[1:] # 例如x的形状是[1, 16, 2],取出的size形状是[16, 2]
num_features=1
for s in size:# s的值分别为16,2,依次相乘,则为数据总数量
num_features*=s
return num_features # 返回的类型是int,一个数字
查看模型参数
for i in model.parameters():
print(i.shape)
创建模型类的对象,定义损失函数和优化器
model = Net().to(device)
loss_function = nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)#建立优化器实例
print(model)
测试模型性能
这个函数是测试用来测试x_test y_test 数据
def eval(model): # 返回的是这10个 测试数据的平均loss
test_epoch_loss=[]
with torch.no_grad():
optimizer.zero_grad()
for i in range(0,10):
y_pre = model(x_test[i])
y_tru=torch.Tensor([y_test[i]]).to(device)
test_loss = loss_function(y_pre,y_tru)
test_epoch_loss.append(test_loss.item())
return mean(test_epoch_loss)
定义数组分别存放训练和测试的损失,对整个训练过程重复epochs次迭代,每一次迭代中,需要逐个将训练集中的个体放入模型进行训练,
epochs =100
sum_train_epoch_loss=[] # 存储每个epoch 下 训练train数据的loss
sum_test_epoch_loss=[] # 存储每个epoch 下 测试 test数据的loss
for epoch in range(epochs):
epoch_loss=[]
for i in range(0,85):
#清除网络先前的梯度值
optimizer.zero_grad()
y_pred = model(x_train[i])
y_true=torch.Tensor([y_train[i]]).to(device)
#训练过程中,正向传播生成网络的输出,计算输出和实际值之间的损失值
print("y_pred:",y_pred,",y_true:",y_true)
single_loss = loss_function(y_pred,y_true)
epoch_loss.append(single_loss.item())
single_loss.backward()#调用backward()自动生成梯度
optimizer.step()#使用optimizer.step()执行优化器,把梯度传播回每个网络
train_epoch_loss=mean(epoch_loss)
test_epoch_loss=eval(model)#返回的是这10个 测试数据的平均loss
sum_train_epoch_loss.append(train_epoch_loss)
sum_test_epoch_loss.append(test_epoch_loss)
print("epoch:"+str(epoch)+" train_epoch_loss: "+str(train_epoch_loss)+" test_epoch_loss: "+str(test_epoch_loss))
tensorflow
model.fit()
dataloader使用
# 构造数据加载类
class mydataset(Dataset):
def __init__(self,data_x,data_y_source): # 读取加载数据 torch.tensor
self._x=data_x
self._y=data_y_source
self._len=data_y_source.shape[0]
def __getitem__(self,item):
return self._x[item],self._y[item]
def __len__(self):# 返回整个数据的长度
return self._len
# 划分 训练集 测试集
data_dataset=mydataset(data_x,data_y_source) # data_x是训练数据,data_y_source是标签,数据要对齐
train_data,test_data=random_split(data_dataset,[round(0.8*data_dataset._len),round(0.2*data_dataset._len)])#这个参数有的版本没有 generator=torch.Generator().manual_seed(0)
# 随机混乱顺序划分的 四舍五入
# 将训练和测试数据集放入dataloader中,可以设置batch进行训练
epochs =100
batch_size=10
test_loader = DataLoader(test_data, batch_size = batch_size, shuffle = True, num_workers = 0 , drop_last=False)
train_loader = DataLoader(train_data, batch_size = batch_size, shuffle = True, num_workers = 0 , drop_last=False)
调试tip总结
池化层定义
torch:两种定义方法
# 1
# __init__()
self.pool = nn.MaxPool2d(2, 2) # 平均池化层是nn.AvgPool2d
# forward()
x = self.pool(x)
# 2
import torch.nn.functional as F
# forward()
x = F.max_pool2d(x, 2) # 平均池化层是F.avg_pool2d
激活函数
# sigmoid
# __init__()
self.sigmoid = torch.nn.Sigmoid()
# forward()
x = self.sigmoid(x)
# softmax
# __init__()
self.softmax = torch.nn.Softmax(dim = 1) # 或 dim = 0
# forward()
x = self.softmax(x)
# relu
# __init__()
self.relu= torch.nn.ReLU()
# forward()
x = self.relu(x)
# tanh
# __init__()
self.tanh= torch.nn.Tanh()
# forward()
x = self.tanh(x)
优化器
# 集合,使用多种优化器预测
# 不同优化器不同的定义方法
net_SGD = Net()
net_Momentum = Net()
net_RMSProp = Net()
net_Adam = Net()
nets = [net_SGD, net_Momentum, net_RMSProp, net_Adam]
opt_SGD = torch.optim.SGD(net_SGD.parameters(), lr=LR)
opt_Momentum = torch.optim.SGD(net_Momentum.parameters(), lr=LR, momentum=0.9)
opt_RMSProp = torch.optim.RMSprop(net_RMSProp.parameters(), lr=LR, alpha=0.9)
opt_Adam = torch.optim.Adam(net_Adam.parameters(), lr=LR, betas=(0.9, 0.99))
optimizers = [opt_SGD, opt_Momentum, opt_RMSProp, opt_Adam]
LSTM
# forward()
x=torch.Tensor(x).to(device)
# x.shape = [500, 12]
x=x.unsqueeze(1) # LSTM的输入是三维的,二维数据进来要多加一个维度
# x.shape = [500, 1, 12]
lstm_out,(h_n,h_c) = self.lstm_1(x,None)
# lstm_out.shape = [500, 1, 128], type(lstm_out) = <class 'torch.Tensor'>
prediction=lstm_out[-1]
# prediction.shape = [1, 128], type(prediction) = <class 'torch.Tensor'>
# prediction就是一维张量,可以直接放入全连接层
prediction = self.linear_1(prediction)
CNN
没有batch的情况
# forward()
x=torch.Tensor(x).to(device)
# x.shape = [500, 12]
x=x.unsqueeze(0) #CNN的输入是三维的,二维数据进来要多加一个维度
# x.shape = [1, 500, 12]
x=self.conv1(x)
# x.shape = [1, 12, 11]
x=self.Sigmoid(x)
# x.shape = [1, 12, 11]
x=F.max_pool2d(x,(2,2))
# x.shape = [1, 6, 5]
x=self.conv2(x)
# x.shape = [1, 16, 2]
x=self.Sigmoid(x)
# x.shape = [1, 16, 2]
x=x.view(-1,self.num_flat_features(x))
# x.shape =
x=self.fc1(x)
...
使用了数据加载器,设置了batch_size的情况,x需要转换一下维度
# forward()
# x.shape = [10, 600, 12]
x.transpose(0,1) # x需要转换一下维度
x=torch.Tensor(x).to(device)
# x.shape = [1, 500, 12]
x=self.Sigmoid(self.conv1(x))
# x.shape = [1, 12, 11]
x=x.view(-1,self.num_flat_features(x))
# x.shape = [10, 132]
x=self.Sigmoid(self.fc1(x))
# x.shape = [10, 66]
x=self.Sigmoid(self.fc2(x))
# x.shape = [10, 33]
x=self.fc3(x)
# x.shape = [10, 1]
...
写csv
为csv添加表头
import pandas as pd
df = pd.read_csv('tf.csv',header=None,names=['a','b','c','d','e','f','g','h','i','j','k'])
df.to_csv('tf.csv',index=False) # 先存再写
plt.plot(list(nums_zd.keys()),list(nums_zd.values()),'o-',color = 'r',label="CNN-RLSTM")
plt.legend() # 有这句话,上面定义的label="CNN-RLSTM"才会显示出来
模型保存
model = Net()