深度学习之PyTorch

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))





©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,539评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,911评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,337评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,723评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,795评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,762评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,742评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,508评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,954评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,247评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,404评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,104评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,736评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,352评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,557评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,371评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,292评论 2 352

推荐阅读更多精彩内容