相比起keras和tensorflow,个人感觉pytorch更好一些
 相比起程序语言本身,个人感觉,记住解决问题的步骤和方法更重要
 import torch
 t=torch.tensor(1)
 t.size()
 t1=torch.rand((3,4))
 torch.Tensor?
 torch.empty((3,3))
 device=torch.device('cuda' if torch.cuda.is_available() else 'cpu')#实例化device
 torch.zeros((2,3),device=device)
 a=torch.zeros((2,3))
 a.to(device)
 # device=torch.device('cpu')#cpu设备,放tensor到cpu上跑
 a.to(device)#下面不带device='cuda:0'
 x=torch.ones((2,2),requires_grad=True)
 print(x)#需要梯度
 y=x+2#grad_fn里面保存了当前操作,add
 print(y)
 z=y*y*3#grad_fn里面保存了当前操作,复合运算
 print(z)
 out=z.mean()#grad_fn求均值的操作,Mean
 print(out)
 a=torch.rand(2,2)# requires_grad默认是False
 a=(a*3)/(a-1)
 print(a.requires_grad,type(a))
 a.requires_grad=True
 print(a.requires_grad)
 b=(a*a).sum()
 with torch.no_grad():# 指定不保留计算梯度的操作
     c=(a*a).sum()
     print(c,c.requires_grad)
 out.backward()# 此时能计算出out对x的导数
 print(a,a.data)#a的requires_grad=True时,只显示a的数据a.data
 a.numpy()# 当requires_grad=True时,用tensortensor.detach().numpy(),相当于深拷贝
 import numpy as np
 np.set_printoptions(suppress=True)
 x=np.random.rand(500,1)
 #准备数据,输入和输出
 x=torch.rand(500,1)
 y=3*x+0.8 #y_true
 #初始化w,b
 w=torch.rand((1,1),requires_grad=True)#w必须初始化为一个2维的tensor
 b=torch.rand(1,requires_grad=True)
 w_i=torch.rand(1,requires_grad=True)# 一维的tensor
 w_i.dim()# 
 learning_rate=1e-2
 np.set_printoptions(suppress=True)
 #迭代,反向传播,更新参数
 for i in range(2000):
     #计算预测值和损失
     y_pre=torch.matmul(x,w)+b
     loss=(y-y_pre).pow(2).mean()
     if w.grad is not None:# .data属于浅拷贝,改变的话,原数据也改变
         w.grad.data.zero_()#如果w.grad不为None,就归0,不然会累加
     if b.grad is not None:
         b.grad.data.zero_()
     loss.backward()# 反向传播
     w.data-=learning_rate*w.grad#更新梯度
     b.data-=learning_rate*b.grad
     if i%50==0:
         print('w,b,loss:',w.item(),b.item(),loss.item())
 import matplotlib.pyplot as plt
 plt.figure(figsize=(20,10))
 plt.rcParams['font.size']=20
 plt.scatter(x.numpy(),y.numpy(),c='red')# detach属于深拷贝
 plt.plot(x,y_pre.detach().numpy(),c='blue')# y_pre.detach().numpy()
 plt.show()
 from torch import nn
 #定义模型
 class MyModel(nn.Module):
     def __init__(self):
         super(MyModel,self).__init__()
         self.linear=nn.Linear(1,1)#输入特征,输出特征
     def forward(self,x):# 前向传播
         output=self.linear(x)
         return output#预测值
 from torch import optim
 device=torch.device('cuda'\
 if torch.cuda.is_available() else 'cpu')#实例化device
 x=torch.rand(500,1).to(device)# 可以变成gpu或cpu下的tensor
 y_true=(3*x+0.8)# 因为x是gpu下tensor,y也被变了
 print(x[:5],y_true[:5])
 model=MyModel().to(device)#其他在模型内的参数等也会变成gpu下的tensor
 yhq=optim.SGD(model.parameters(),5e-3)#优化器,parameters()在模型内,也被变成gpu tensor
 loss_fn=nn.MSELoss()
 #迭代,梯度下降,参数更新
 for i in range(5000):
     y_pre=model(x)# 预测值,自动调用_call方法,_call调用forward方法
     loss=loss_fn(y_true,y_pre)#更新损失
     yhq.zero_grad()#梯度归0
     loss.backward()#反向传播
     yhq.step()#更新参数
     if i%100==0:
         print('loss,params:',loss.item(),\
               list(model.parameters())[0].item(),\
               list(model.parameters())[1].item())
 # model.eval()# 表示设置模型为预测模式
 # model.train(True)#表示设置模型为训练模式
 from torch.utils.data import Dataset
 data_path=r'C:\Users\li\Downloads\train.txt'
 class MyDataset(Dataset):
     def __init__(self):
         self.lines=open(data_path,encoding='utf8').readlines()
     def __getitem__(self,index):
         line= self.lines[index].strip()
 #         print(line)
         text,label=line.split('\t')
         return text,label
     def __len__(self):
         return len(self.lines)
 from torch.utils.data import DataLoader
 mydataset=MyDataset()
 dataloader=DataLoader(mydataset,batch_size=32,shuffle=True)
 from torchvision.datasets import MNIST
 from torchtext.datasets import IMDB
 # root是存放数据集的路径,可以没有,没有就自动创建,download,True下载数据集
 mnist=MNIST(root='./datasets',train=True,download=False)
 plt.figure(figsize=(1,1))
 plt.imshow(mnist[0][0],cmap='grey')
 data=np.random.randint(0,255,24)
 img=data.reshape(2,4,3)# 模拟的一个图片,h,w,c,图片数据在0-255
 from torchvision import transforms
 # 用transforms将图片数据转换成tensor(c,h,w),用了permute()方法
 img_tensor=transforms.ToTensor()(img)
 tensor=torch.Tensor(img)
 # print(tensor)
 # tensor.transpose(2,0)
 tensor.permute(2,0,1)#可以交换轴
  ret=transforms.ToTensor()(mnist[0][0])# 将ndarray转换成c,h,w这样的结构
 # print(ret.size())
 from torch.optim import Adam#梯度和梯度加总都做了ema处理
 def get_dataloader(flag=True,batch_size=128):# 每批次128个
         # 数据集,手写辨识,变成了tensor,做了标准化处理
     mnist=MNIST(root='./datasets',train=flag,download=False,
                transform=transforms.Compose(
                [transforms.ToTensor(),#把原来的ndarray(h,w,c)变成饿了(c,h,w)
                 #传入的均值和标准差必须和数据集中图片的通道数一致,3通道得3个
                 transforms.Normalize((0.1307,),(0.3081,))
                ])
                )
     print(len(mnist))
     return DataLoader(mnist,batch_size=batch_size,shuffle=True)
 class MnistNet(nn.Module):
     def __init__(self):
         super(MnistNet,self).__init__()
         self.fc1=nn.Linear(1*28*28,28)#全连接1层28*28--->28
         self.fc2=nn.Linear(28,10)# 输出层28-->10
     def forward(self,input_):
         # -1是batchsize,但batchsize是向上取整,最后那个不一样,写-1,让电脑弄
         # 要么input_.size(0),view相当于reshape
         #修改数据形状,相当于keras中的Flattern
         x=input_.view(-1,28*28*1)#这里不能写死了,因为test时,batch_size大
         # 全连接
         x=self.fc1(x)# 这样内部就进行矩阵操作,输出28*1,线性运算
         x=nn.functional.relu(x)# 激活函数处理,形状不变
         # 输出层
         output=self.fc2(x)# 经过输出层处理,28-->10
         #交叉熵损失,对输出值计算概率和取对数
         return nn.functional.log_softmax(output,dim=-1)
 import os
 my_model=MnistNet()
 #训练,loss:min_loss:0.0556986965239048,loss:0.05224079266190529
 optimizer=Adam(my_model.parameters(),lr=5e-4)# parameters()带括号
 # 如果路径存在就加载模型,不存在就是新建的模型
 if os.path.exists('./model/mnist_model_best_6_5.pkl'):
     my_model.load_state_dict(torch.load('./model/mnist_model_best_6_5.pkl'))
     optimizer.load_state_dict(torch.load('./results/mnist_optim_best_6_5.pkl'))
 def train(epoch):
     # 每次epoch都会初始化成这个值,但一次epoch内这个值会
     #取最小
     min_loss=torch.tensor(1000)
     dataloader=get_dataloader()#默认是train=True,batchsize=128
     print('epoch:',epoch+1,len(dataloader))#迭代次数,批次
     for inx,(data,label) in enumerate(dataloader):
         optimizer.zero_grad()# 把之前的梯度归零
         y_pre=my_model(data)#根据data预测,会调用模型的forward方法
         # 真实值乘概率的对数,计算损失,多元交叉熵
         cur_loss=nn.functional.nll_loss(y_pre,label)
         cur_loss.backward()#反向传播,对x求导的过程
         optimizer.step()# 更新梯度
         #小于min_loss才改值,确保min_loss是最小值
         if cur_loss<min_loss:# 如果loss比min_loss小,保存模型
             torch.save(my_model.state_dict(),\
                        './model/mnist_model_best_7_{}.pkl'\
                        .format(epoch+1))#保存模型参数,state_dict必须带括号
             torch.save(optimizer.state_dict(),\
                        './results/mnist_optim_best_7_{}.pkl'\
                        .format(epoch+1))# 保存优化器
             print('模型保存成功,之前的min_loss:{:.6f},当前loss:{:.6f}'\
                   .format(min_loss.item(),cur_loss.item()))
             min_loss=cur_loss# 更改min_loss为当前loss
         if inx%50==0:# 每隔50个batch打印
             print('train epoch:{}[{}/{}({:.0f}%)]\tLoss:{:.6f}'\
                  .format(epoch+1,(inx+1)*len(data),len(dataloader.dataset),\
                  100.*(inx+1)/len(dataloader),cur_loss.item()        
             ))
   for i in range(5):# 迭代5次
     train(i)
 def test(model):
     loss_lst=[]
     acc_lst=[]
     model.eval()
     test_dataloader=get_dataloader(flag=False,batch_size=1000)
     with torch.no_grad():#不计算梯度,测试状态
         for idx,(data,label) in enumerate(test_dataloader):
                 output=model(data)# 输出(样本数,10)
                 #计算的是一个batch的损失
                 cur_loss=nn.functional.nll_loss(output,label)
     #             print(output.shape)
                 y_pred=output.max(dim=-1)[-1]# 长度2,最大值和对应的类别
                 # float()之后有1有0,求它的均值就是求和之后/总样本数
                 cur_acc=y_pred.eq(label).float().mean()
     #             print(cur_acc)
         #         print(label[0])# 一维张量
                 loss_lst.append(cur_loss)
                 acc_lst.append(cur_acc)
         return np.mean(loss_lst),np.mean(acc_lst)
 for i in range(5):
     my_model=MnistNet()
     optimizer=Adam(my_model.parameters(),lr=5e-4)# parameters()带括号
     my_model.load_state_dict(torch\
                  .load('./model/mnist_model_best_6_{}.pkl'.format(i+1)))
     optimizer.load_state_dict(torch\
                   .load('./results/mnist_optim_best_6_{}.pkl'.format(i+1)))
     loss,acc=test(my_model)
     print(loss,acc)
     del my_model