PyTorch入门精简资料(二)设立计算图并自动计算

Datawhale_Task2     设立计算图并自动计算

  1. numpy和pytorch实现梯度下降法
  2. 设定初始值
  3. 求取梯度
  4. 在梯度方向上进行参数的更新
  5. numpy和pytorch实现线性回归
  6. pytorch实现一个简单的神经网络
  7. 参考资料:PyTorch 中文文档 https://pytorch.apachecn.org/docs/1.0/

1.numpy和pytorch实现梯度下降法

(1)numpy实现梯度下降

x = 1
lr= 0.1 #学习率
epochs = 2
y = lambda x : x**2 + 5*x + 1 

for epoch in range(epochs):
    dx = 2*x + 5 
    x = x - lr*dx  
print(x)

(2)pytorch实现梯度下降

import torch
from torch.autograd import Variable

x = torch.FloatTensor([1])
print('grad',x.grad,'data',x.data)
learning_rate = 0.1
epoches = 10

for epoch in range(epoches):
    x = Variable(x, requires_grad=True)
    y = x**2+5*x+1
    y.backward()
    x.data = x.data - learning_rate*x.grad.data
    print('grad',x.grad.data, 'data',x.data)  #打印梯度值,更新后的x
    x.grad.data.zero_()   #梯度归零
print(x.data)

(3)numpy实现线性回归

import torch
import torch.nn as nn
import numpy as np
from torch.autograd import Variable
import matplotlib.pyplot as plt

# Linear regression model
def model(x):
    return [email protected]()+b   # @ 代表pytorhc中矩阵乘法,.t()返回一个张量的转置
def  mse(t1,t2):
    diff = t1-t2
    return torch.sum(diff*diff)/diff.numel()

# Hyper-parameters
epoches=1000
lr = 1e-4

# Toy dataset
x_train = np.array([[73,67,43], [91,88,64],[87,134,37],[102,43,37],[69,96,70]],dtype=np.float32)
y_train = np.array([[56,70],[81,101],[119,133],[22,37],[103,119]], dtype=np.float32)
# x_train = torch.from_numpy(x_train)
# y_train = torch.from_numpy(y_train)
# Weights and bias
w = torch.randn(2 ,3)  # , equires_gard=True
b = torch.randn(2)

for epoch in range(epoches):
    x_train = torch.from_numpy(x_train)
    y_train = torch.from_numpy(y_train)
    w = Variable(w, requires_grad=True)
    b = Variable(b, requires_grad=True)
    preds = model(x_train)
    loss = mse(preds, y_train)
    loss.backward()
    w.data -= w.grad.data * lr
    b.data -= b.grad.data * lr
    w.grad.zero_()
    b.grad.zero_()
    if (epoch + 1) % 5 == 0:
        print('Epoch [{}/{}], Loss: {:.4f}'.format(epoch + 1, epoches, loss.item()))

(4)pytorch实现线性回归

import torch
from torch.autograd import Variable

epoches = 100
lr = 1e-4

# train data
x_data = Variable(torch.Tensor([[1.0], [2.0], [3.0]]))
y_data = Variable(torch.Tensor([[2.0], [4.0], [6.0]]))

class Model(torch.nn.Module):
    def __init__(self):
        super(Model, self).__init__()
        self.linear = torch.nn.Linear(1, 1)  # One in and one out

    def forward(self, x):
        y_pred = self.linear(x)
        return y_pred

# our model
model = Model()

criterion = torch.nn.MSELoss(size_average=False)  # Defined loss function
optimizer = torch.optim.SGD(model.parameters(), lr=lr)  # Defined optimizer

# Training: forward, loss, backward, step
# Training loop
for epoch in range(epoches):
    # Forward pass
    y_pred = model(x_data)
    # Compute loss
    loss = criterion(y_pred, y_data)
    #print(epoch, loss.data[0])
    # Zero gradients
    optimizer.zero_grad()
    # perform backward pass
    loss.backward()
    # update weights
    optimizer.step()
    if (epoch + 1) % 5 == 0:
        print('Epoch [{}/{}], Loss: {:.4f}'.format(epoch + 1, epoches, loss.item()))  #loss.data

(5)pytorch实现一个简单的神经网络 (LeNet5)

数据转换处理部分见 PyTorch入门精简资料(二)

# coding: utf-8

import torch
from torch.utils.data import DataLoader
import torchvision.transforms as transforms
import numpy as np
import os
from torch.autograd import Variable
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
import sys
sys.path.append("..")
from torch.utils.data import Dataset
#from utils.utils import MyDataset, validate, show_confMat
from tensorboardX import SummaryWriter
from datetime import datetime
import matplotlib.pyplot as plt
from PIL import Image

class MyDataset(Dataset):
    def __init__(self, txt_path, transform = None, target_transform = None):
        fh = open(txt_path, 'r')
        imgs = []
        count=0
        for line in fh:
            line = line.rstrip()
            words = line.split()
            if count == 60001:
                print(count,'words----------------',words[0],int(words[1]))
            count += 1
            imgs.append((words[0], int(words[1])))
        #print(imgs[:-1])

        self.imgs = imgs    # 最主要就是要生成这个list, 然后DataLoader中给index,通过getitem读取图片数据
        self.transform = transform
        self.target_transform = target_transform

    def __getitem__(self, index):
        fn, label = self.imgs[index]
        img = Image.open(fn).convert('L')     # 像素值 0~255,在transfrom.totensor会除以255,使像素值变成 0~1

        if self.transform is not None:
            img = self.transform(img)   # 在这里做transform,转为tensor等等

        return img, label

    def __len__(self):
        return len(self.imgs)

def validate(net, data_loader, set_name, classes_name):
    """
    对一批数据进行预测,返回混淆矩阵以及Accuracy
    :param net:
    :param data_loader:
    :param set_name:  eg: 'valid' 'train' 'tesst
    :param classes_name:
    :return:
    """
    net.eval()
    cls_num = len(classes_name)
    conf_mat = np.zeros([cls_num, cls_num])

    for data in data_loader:
        images, labels = data
        images = Variable(images)
        labels = Variable(labels)

        outputs = net(images)
        outputs.detach_()

        _, predicted = torch.max(outputs.data, 1)

        # 统计混淆矩阵
        for i in range(len(labels)):
            cate_i = labels[i].numpy()
            pre_i = predicted[i].numpy()
            conf_mat[cate_i, pre_i] += 1.0

    for i in range(cls_num):
        print('class:{:<10}, total num:{:<6}, correct num:{:<5}  Recall: {:.2%} Precision: {:.2%}'.format(
            classes_name[i], np.sum(conf_mat[i, :]), conf_mat[i, i], conf_mat[i, i] / (1 + np.sum(conf_mat[i, :])),
                                                                conf_mat[i, i] / (1 + np.sum(conf_mat[:, i]))))

    print('{} set Accuracy:{:.2%}'.format(set_name, np.trace(conf_mat) / np.sum(conf_mat)))

    return conf_mat, '{:.2}'.format(np.trace(conf_mat) / np.sum(conf_mat))

# def show_confMat(confusion_mat, classes, set_name, out_dir):
#
#     # 归一化
#     confusion_mat_N = confusion_mat.copy()
#     for i in range(len(classes)):
#         confusion_mat_N[i, :] = confusion_mat[i, :] / confusion_mat[i, :].sum()
#
#     # 获取颜色
#     cmap = plt.cm.get_cmap('Greys')  # 更多颜色: http://matplotlib.org/examples/color/colormaps_reference.html
#     plt.imshow(confusion_mat_N, cmap=cmap)
#     plt.colorbar()
#
#     # 设置文字
#     xlocations = np.array(range(len(classes)))
#     plt.xticks(xlocations, list(classes), rotation=60)
#     plt.yticks(xlocations, list(classes))
#     plt.xlabel('Predict label')
#     plt.ylabel('True label')
#     plt.title('Confusion_Matrix_' + set_name)
#
#     # 打印数字
#     for i in range(confusion_mat_N.shape[0]):
#         for j in range(confusion_mat_N.shape[1]):
#             plt.text(x=j, y=i, s=int(confusion_mat[i, j]), va='center', ha='center', color='red', fontsize=10)
#     # 保存
#     plt.savefig(os.path.join(out_dir, 'Confusion_Matrix' + set_name + '.png'))
#     plt.close()

train_txt_path = os.path.join(".", "data", "train.txt")
valid_txt_path = os.path.join(".", "data", "test.txt")

#classes_name = ['plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck']
classes_name = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']

train_bs = 10
valid_bs = 10
lr_init = 0.001
max_epoch = 2

# log
result_dir = os.path.join("..", "Result")

now_time = datetime.now()
time_str = datetime.strftime(now_time, '%m-%d_%H-%M-%S')

log_dir = os.path.join(result_dir, time_str)
if not os.path.exists(log_dir):
    os.makedirs(log_dir)

writer = SummaryWriter(log_dir=log_dir)

# ------------------------------------ step 1/5 : 加载数据------------------------------------

# 数据预处理设置
# normMean = [0.4948052, 0.48568845, 0.44682974]
# normStd = [0.24580306, 0.24236229, 0.2603115]
normMean = [0.5]
normStd = [0.5]
normTransform = transforms.Normalize(normMean, normStd)
trainTransform = transforms.Compose([
    #transforms.Resize(32),
    #transforms.RandomCrop(32, padding=4),
    transforms.ToTensor(),
    normTransform
])

validTransform = transforms.Compose([
    transforms.ToTensor(),
    normTransform
])

# 构建MyDataset实例
train_data = MyDataset(txt_path=train_txt_path, transform=trainTransform)
valid_data = MyDataset(txt_path=valid_txt_path, transform=validTransform)

# 构建DataLoder
train_loader = DataLoader(dataset=train_data, batch_size=train_bs, shuffle=True)
valid_loader = DataLoader(dataset=valid_data, batch_size=valid_bs)

# ------------------------------------ step 2/5 : 定义网络------------------------------------


class LetNet5(nn.Module):
    def __init__(self, num_clases=10):
        super(LetNet5, self).__init__()

        self.c1 = nn.Sequential(
            nn.Conv2d(1, 6, kernel_size=5, stride=1, padding=2),
            nn.BatchNorm2d(6),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2)
        )

        self.c2 = nn.Sequential(
            nn.Conv2d(6, 16, kernel_size=5),
            nn.BatchNorm2d(16),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2)
        )

        self.c3 = nn.Sequential(
            nn.Conv2d(16, 120, kernel_size=5),
            nn.BatchNorm2d(120),
            nn.ReLU()
        )

        self.fc1 = nn.Sequential(
            nn.Linear(120, 84),
            nn.ReLU()
        )

        self.fc2 = nn.Sequential(
            nn.Linear(84, 10),
            nn.LogSoftmax()
        )

    def forward(self, x):
        out = self.c1(x)
        out = self.c2(out)
        out = self.c3(out)
        out = out.reshape(out.size(0), -1)
        out = self.fc1(out)
        out = self.fc2(out)
        return out

    # 定义权值初始化
    def initialize_weights(self):
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                torch.nn.init.xavier_normal_(m.weight.data)
                if m.bias is not None:
                    m.bias.data.zero_()
            elif isinstance(m, nn.BatchNorm2d):
                m.weight.data.fill_(1)
                m.bias.data.zero_()
            elif isinstance(m, nn.Linear):
                torch.nn.init.normal_(m.weight.data, 0, 0.01)
                m.bias.data.zero_()


net = LetNet5()     # 创建一个网络
net.initialize_weights()    # 初始化权值

# ------------------------------------ step 3/5 : 定义损失函数和优化器 ------------------------------------

criterion = nn.CrossEntropyLoss()                                                   # 选择损失函数
optimizer = optim.SGD(net.parameters(), lr=lr_init, momentum=0.9, dampening=0.1)    # 选择优化器
scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=50, gamma=0.1)     # 设置学习率下降策略

# ------------------------------------ step 4/5 : 训练 --------------------------------------------------

for epoch in range(max_epoch):

    loss_sigma = 0.0    # 记录一个epoch的loss之和
    correct = 0.0
    total = 0.0
    scheduler.step()  # 更新学习率

    for i, data in enumerate(train_loader):
        # if i == 30 : break
        # 获取图片和标签
        inputs, labels = data
        inputs, labels = Variable(inputs), Variable(labels)

        # forward, backward, update weights
        optimizer.zero_grad()
        outputs = net(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()

        # 统计预测信息
        _, predicted = torch.max(outputs.data, 1)
        total += labels.size(0)
        correct += (predicted == labels).squeeze().sum().numpy()
        loss_sigma += loss.item()

        # 每10个iteration 打印一次训练信息,loss为10个iteration的平均
        if i % 10 == 9:
            loss_avg = loss_sigma / 10
            loss_sigma = 0.0
            print("Training: Epoch[{:0>3}/{:0>3}] Iteration[{:0>3}/{:0>3}] Loss: {:.4f} Acc:{:.2%}".format(
                epoch + 1, max_epoch, i + 1, len(train_loader), loss_avg, correct / total))

            # 记录训练loss
            writer.add_scalars('Loss_group', {'train_loss': loss_avg}, epoch)
            # 记录learning rate
            writer.add_scalar('learning rate', scheduler.get_lr()[0], epoch)
            # 记录Accuracy
            writer.add_scalars('Accuracy_group', {'train_acc': correct / total}, epoch)

    # 每个epoch,记录梯度,权值
    for name, layer in net.named_parameters():
        writer.add_histogram(name + '_grad', layer.grad.cpu().data.numpy(), epoch)
        writer.add_histogram(name + '_data', layer.cpu().data.numpy(), epoch)

    # ------------------------------------ 观察模型在验证集上的表现 ------------------------------------
    if epoch % 2 == 0:
        loss_sigma = 0.0
        cls_num = len(classes_name)
        conf_mat = np.zeros([cls_num, cls_num])  # 混淆矩阵
        net.eval()
        for i, data in enumerate(valid_loader):

            # 获取图片和标签
            images, labels = data
            images, labels = Variable(images), Variable(labels)

            # forward
            outputs = net(images)
            outputs.detach_()

            # 计算loss
            loss = criterion(outputs, labels)
            loss_sigma += loss.item()

            # 统计
            _, predicted = torch.max(outputs.data, 1)
            # labels = labels.data    # Variable --> tensor

            # 统计混淆矩阵
            for j in range(len(labels)):
                cate_i = labels[j].numpy()
                pre_i = predicted[j].numpy()
                conf_mat[cate_i, pre_i] += 1.0

        print('{} set Accuracy:{:.2%}'.format('Valid', conf_mat.trace() / conf_mat.sum()))
        # 记录Loss, accuracy
        writer.add_scalars('Loss_group', {'valid_loss': loss_sigma / len(valid_loader)}, epoch)
        writer.add_scalars('Accuracy_group', {'valid_acc': conf_mat.trace() / conf_mat.sum()}, epoch)
print('Finished Training')

# ------------------------------------ step5: 保存模型 并且绘制混淆矩阵图 ------------------------------------
net_save_path = os.path.join(log_dir, 'net_params.pkl')
torch.save(net.state_dict(), net_save_path)

conf_mat_train, train_acc = validate(net, train_loader, 'train', classes_name)
conf_mat_valid, valid_acc = validate(net, valid_loader, 'valid', classes_name)

#show_confMat(conf_mat_train, classes_name, 'train', log_dir)
#show_confMat(conf_mat_valid, classes_name, 'valid', log_dir)

参考:https://github.com/tensor-yu/PyTorch_Tutorial

https://blog.csdn.net/qinhanmin2010/article/details/98951698

 

你可能感兴趣的:(深度学习)