PyTorch常用导入的包
from modname import *
#把一个模块的所有内容全都导入到当前的命名空间, 不应该过多使用
用from语句可以直接导入子模块,而不需要冗长的前缀来调用模块中的函数
而用import导入子模块,需要使用前缀,所以一般用as来消除前缀
import torch #导入整个模块
import numpy as np
import torch.utils.data as data
from torch.utils.data import DataLoader
import torchvision.transforms as transforms
from torchvision import datasets
from torch.autograd import Variable
import matplotlib
from matplotlib import pyplot as plt
import torch.nn.functional as F
#从模块中导入一个指定的部分到当前命名空间中
Dataset(数据集)
#定义数据类
class myDataset(data.Dataset):
def __init__(self, csv_file, txt_file, root_dir, other_file):
self.csv_data = pd.read_csv(csv_file)
with open(txt_file, 'r') as f:
data_list = f.readlines()
self.txt_data = data_list
self.root_dir = root_dir
def __len__(self):
return len(self.csv_data)
def __getitem__(self, idx):
data = (self.csv_data[idx], self.txt_data[idx])
return data
通过上面的方式,可以定义我们需要的数据类
可以通过迭代的方式来取得每一个数据
但是这样很难实现取batch,shuffle 或者多线程去读取数据
所以PyTorch通过torch.utils.data.DataLoader来定义一个新的迭代器
#定义迭代器:
dataiter = data.DataLoader(myDataset, batch_size = 32,
shuffle = True, collate_fn = default_collate)
#collate_fn是表示如何取样本,我们可以定义自己的函数来准确地
#实现想要的功能,默认的函数一般情况下可以使用
torchvision这个包中有一个计算机视觉数据读取类:ImageFolder,图片是这种形式
1. root/dog/xxx.png
2. root/dog/xxy.png
3. root/dog/xyz.png
之后调用这个类
dset = ImageFolder(root = 'root_path', transform = None,
loader = default_loader)
transform和target_transform是图片增强,loader是图片读取方法,
通过loader将图片转换成我们需要的图片类型进入神经网络
nn.Module(模组)
在Pytorch里编写神经网络,所有的层结构和损失函数都来自于torch.nn, 所有模型的构建都是从这个基类nn.Module继承的,所以有下面这个模板:
class net_name(nn.Module):
def __init__(self, other_arguments):
super(net_name, self).__init__()
self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size)
#other network layer
def forword(self, x):
x = self.conv1(x)
return x
损失函数也在nn模块中定义好了:
criterion = nn.CrossEntropyLoss()
loss = criterion(output,target)
torch.optim(优化)
通过torch.optim包来实现,调用的时候将需要优化的参数传入,这些参数必须是Variable,然后传入一些基本的设定,比如学习率和动量等。
optimizer = torch.optim.SGD(model,parameters(), lr = 0.01,
momentum = 0.9)
优化之前需要先将梯度归零
即optimizer.zeros()
然后通过loss.backward()反向传播,自动求道每个参数的梯度
最后只需要optimizer.step()就可以通过梯度做一步参数更新
模型的保存和加载torch.save
保存有两种方式:
(1)保存整个模型的结构信息和参数信息,保存的对象是模型model
(2)保存模型的参数, 保存的对象是模型的状态model.state_dict()
save的第一个参数是保存对象,第二个是保存路径及名称
torch.save(model, './model.pth')
torch.save(model.state_dict(), './model_state.pth')
加载有两种方式对应保存模型的方式:
(1)加载完整的模型结构和参数信息,使用load_model = torch.load('model.pth'),网络较大时加载时间较长,同时存储空间较大。
(2)加载模型的参数信息,需要先导入模型的结构,然后通过model.load_state_dic(torch.load('model_state.pth'))来导入
一维线性回归的代码实现
x_train = np.array([[3.3],[4.4],[5.5],[6.71],
[6.93],[4.168],[9.779],[6.182],[7.59],[2.167],[7.042],
[10.791],[5.313],[7.997],[3.1]],dtype = np.float32)
y_train = np.array([[1.7],[2.76],[2.09],[3.19],[1.694],[1.573],
[3.366],[2.596],[2.53],[1.221],[2.827],[3.465],
[1.65],[2.904],[1.3]],dtype = np.float32)
#然后可以对numpy.array用matplotlib库画图
pyplot.plot(x_train, y_train) #连线图
pyplot.plot(x_train, y_train, 'go') #绿色圆点的散点图
pyplot.plot(x_train, y_train, 'r-') #红色实线
pyplot.plot(x_train, y_train, 'b^') #蓝色三角形
画好之后用pyplot.show()展示出来
先将numpy.array转换成Tensor
x_train = torch.from_numpy(x_train)
y_train = torch.from_numpy(y_train)
定义一个简单的模型
class LinearRegression(nn.Module):
def __init__(self):
super(LinearRegression, self).__init__()
self.linear = nn.Linear(1,1)
def forward(self, x):
out = self.linear(x)
return out
if torch.cuda.is_available():
model = LinearRegression().cuda()
else :
model = LinearRegression()
定义损失函数和优化函数,这里使用均方误差作为优化函数,使用梯度下降进行优化
criterion = nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr = 1e-3)
接着开始训练模型
num_epochs = 1000
for epoch in range(num_epochs):
inputs = Variable(x_train)
target = Variable(y_train)
#forward
out = model(inputs)
loss = criterion(out, target)
#backward
optimizer.zero_grad()
loss.backward()
optimizer.step()
if (epoch + 1) % 20 == 0:
print('Epoch[{} / {} ], loss: {:.6f}'.format(epoch + 1,
num_epochs, loss.data[0]))
#注意在终端跑中间不能加空的换行
out得到的是前向传播的结果
loss得到损失函数,然后归零梯度,做反向传播和更新参数
loss.data可以取出一个Tensor, 再通过loss.data[0]得到一个int或者float类型的数据,这样我们才能打印相应的数据。
model.eval() #变成测试模式
predict = model(Variable(x_train)) #模型的数据
predict = predict.data.numpy() #变成numpy()数组
pyplot.plot(x_train.numpy(),y_train.numpy(), 'ro',label = "Original data") #将原来的数据用散点图画出
pyplot.plot(x_train.numpy(), predict, label = 'Fitting Line') #模型里的数据用直线画出
pyplot.show()
多项式回归
因为一次线性多项式精度欠佳
y = b + w1 * x + w2 * x^2 + w3 * x^3
首先需要预处理数据,将数据变成一个矩阵的形式
在PyTorch里面使用torch.cat()函数实线Tensor的拼接:
def make_features(x):
x = x.unsqueeze(1) #用help(torch.unsqueeze)查看函数功能
return torch.cat([x ** i for i in range(1, 4)], 1)
#用help(torch.cat)查看函数功能
然后定义好真实的函数:
W_target = torch.FloatTensor([0.5, 3, 2.4]).unsqueeze(1)
b_target = torch.FloatTensor([0.9])
#f(x)就是每次输入一个x得到一个y的真实函数
def f(x):
#Approximated function.
return x.mm(W_target) + b_target[0]
进行训练的时候要采样一些点,可以随机生成一些数来得到每次的训练集:
def get_batch(batch_size = 32):
random = torch.randn(batch_size)
x = make_features(random)
y = f(x)
return Variable(x), Variable(y)
定义模型
class ploy_model(nn.Module):
def __init__(self):
super(ploy_model, self).__init__()
self.ploy = nn.Linear(3, 1)
def forward(self, x):
out = self.ploy(x)
return out
model = ploy_model()
定义损失函数和优化器:
criterion = nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr = 1e-3)
开始训练模型:
epoch = 0
while True:
#Get data
batch_x, batch_y = get_batch()
#Forward pass
output = model(batch_x)
loss = criterion(output, batch_y)
print_loss = loss.data[0]
#Reset gradients
optimizer.zero_grad()
#Backward pass
loss.backward()
#updata parameters
optimizer.step()
epoch += 1
print('epoch:{} loss:{}'.format(epoch, print_loss))
if print_loss < 1e-3:
break
画图#不懂的函数直接参考书本上的解析吧,每次都用help函数代价太大了
x_test = np.linspace(-5,5,50).astype(np.float32)
#linspace生成一个序列,参数为开始,结束和个数
y_test = 0.9+0.5*x_test+np.square(x_test)*3+np.power(x_test,3)*2.4
model.eval()
predict = model(make_features(Variable(torch.from_numpy(x_test))).cuda())
predict = predict.cpu()
predict = predict.data.numpy()
plt.figure()
plt.plot(x_test,y_test,'-r',label = 'Original Data')
plt.scatter(x_test, predict)
plt.legend()
plt.show()
Logistic回归的代码实现
设定随机数种子:
torch.manual_seed(2018)
1.读取数据
with open('./Desktop/data.txt', 'r') as f:
data_list = f.readlines()
data_list = [i.split('\n')[0] for i in data_list]
data_list = [i.split(',') for i in data_list]
data = [(float(i[0]), float(i[1]), float(i[2])) for i in data_list]
#标准化数据
x0_max = max([i[0] for i in data])
x1_max = max([i[1] for i in data])
data = [(i[0] / x0_max, i[1]/ x1_max, i[2]) for i in data])
#转换数据
np_data = np.array(data, dtype='float32') # 转换成 numpy array
x_data = torch.from_numpy(np_data[:, 0:2]) # 转换成 Tensor, 大小是 [100, 2]
y_data = torch.from_numpy(np_data[:, -1]).unsqueeze(1) # 转换成 Tensor,大小是 [100, 1]
2.用matplotlib将数据画出来
x0 = list(filter(lambda x: x[-1] == 0.0, data)) #选择第一类的点
x1 = list(filter(lambda x: x[-1] == 1.0, data)) #选择第二类的点
plot_x0 = [i[0] for i in x0]
plot_y0 = [i[1] for i in x0]
plot_x1 = [i[0] for i in x1]
plot_y1 = [i[1] for i in x1]
x_data = torch.Tensor([i[0] for i in data])
y_data = torch.Tensor([i[1] for i in data])
# 定义 sigmoid 函数
def sigmoid(x):
return 1 / (1 + np.exp(-x))
# 画出 sigmoid 的图像
plot_x = np.arange(-10, 10.01, 0.01)
plot_y = sigmoid(plot_x)
plt.plot(plot_x, plot_y, 'r')
#画出data.txt中的数据点
plt.plot(plot_x0_0, plot_x0_1, 'ro', label = 'x_0')
plt.plot(plot_x1_0, plot_x1_1, 'bo', label='x_1')
plt.legend(loc = 'best')
plt.show()
3.定义Logistic回归的模型以及而分类问题的损失函数和优化方法
class LogisticRegression(nn.Module):
def __init__(self):
super(LogisticRegression, self).__init__()
self.lr = nn.Linear(2, 1)
self.sm = nn.Sigmoid()
def forward(self, x):
x = self.lr(x)
x = self.sm(x)
return x
logistic_model = LogisticRegression()
criterion = nn.BCELoss()#二分类损失函数
optimizer = torch.optim.SGD(logistic_model.parameters(), lr = 1e-3,
momentum = 0.9)
4.训练模型
for epoch in range(50000):
x = Variable(x_data)
y = Variable(y_data)
#forward
out = logistic_model(x)
loss = criterion(out, y)
print_loss = loss.data[0]
mask = out.ge(0.5).float()
correct = (mask == y).sum()
acc = correct.data[0] / x.size(0)
#backward
optimizer.zero_grad()
loss.backward()
optimizer.step()
if (epoch + 1) % 1000 == 0:
print('*' * 10)
print('epoch {}'.format(epoch + 1))
print('loss is {:.4f}'.format(print_loss))
print('acc is {:.4f}'.format(acc))