Datawhale_Task2 设立计算图并自动计算
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