刘二老师的代码合集

一、感谢

首先谢谢刘老师的视频课,我没有白嫖,我点赞投币了,哈哈哈哈,刘老师讲的很好,感谢,同时感谢吴恩达老师的深度学习的课程,很随和、亲和。谢谢

还要谢谢CSDN博主(大佬):错错莫、whut_L、LoveMIss-Y。学习刘老师代码,经常翻看三位大佬的博客,学到很多。谢谢

二、上传目的

书写以做记录,自己打的注释,有很多代码没有打清楚,也没有打对,所以仅自己参考,不喜勿喷,写错的请路过的大佬指出来,非常感谢。

是根据刘老师的视频复刻的代码。里面自己也有很多不懂的。

里面的逻辑、流程、还有一些个别的代码,的注释,包括最后的RNN中的GRU模型的代码注释,自己还是打的不太好。后面自己会补上的,不过要好久了。大家可以帮忙纠错,谢谢。一起学习。

废话:

里面还有很多不懂的地方,自己感觉pytorch书写,是把模型用代码的形式表现出来,个人感觉最难的是参数的设置环节,对pytorch中的模型的参数弄明白了,基本上就懂得差不多了,还有一个就是整体的流程,代码实现的哪一个流程。怎么说呢,代码是没有咱们人这么舒坦(不会用词了),心里有想法,但是用代码可能需要提前准备很多,虽然已经很简便了,但是对于咱们看数学公式,个人感觉还是比较麻烦的,所以自己代码能力还是有待提高。

三、章节

第二节:线性模型

part1:

#加油加油加油
#认真对待每一行代码
#努力写好每一行代码
#搞懂每一行代码
import numpy as np
import matplotlib.pyplot as plt

"""
数据:特征、标签;设置权值:(0,4,0.01)-特征值和不同的w进行变换,
根据损失函数,输出。
"""

#数据集
x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]


def forward(x):
    """
    特征经过网络进行变换得到预测
    特征乘权重;
    :param x: 输入
    :return: x * w;
    """
    return x * w


def loss(x, y):
    """
    求得预测与真实的误差
    :param x: 特征
    :param y: 真实值
    :return: 损失
    """
    y_pred = forward(x)
    return (y_pred - y) * (y_pred - y)


#创建两个空列表;分别用于存放每一次权重值 和 每一次循环的 误差
w_list = []
mes_list = []

for w in np.arange(0.0, 4.1, 0.01):
    """
    进行了0.0-4.1距离;间隔0.01;次循环;进行循环
    损失和,初始化
    取特征集和对应的标签传给x_val,y_val,
    调用forward函数返回y_pred_val预测值;
    调用loss函数返回loss_val损失值
    求损失的和
    输出
    """
    # print('w = ', w)
    l_sum = 0
    for x_val, y_val in zip(x_data, y_data):
        y_pred_val = forward(x_val)
        loss_val = loss(x_val, y_val)
        l_sum += loss_val
        print('\t', x_val, y_val, y_pred_val, loss_val)
    print('MSE = ', l_sum / 3)
    w_list.append(w)
    mes_list.append(l_sum / 3)

#画图:每一次的w为x轴;对应的误差为y轴
plt.plot(w_list, mes_list)
plt.ylabel('Loss')
plt.plot('w')
plt.show()

part2:

#加油加油加油
#认真对待每一行代码
#努力写好每一行代码
#搞懂每一行代码
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D


#创建数据集
x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]


def forward(x):
    """
    返回的是预测值
    :param x: 输入
    :return: 经过网络的输出
    """
    return x * w + b


def loss(x, y):
    """
    返回的是预测值与真实值得平方差
    :param x: 特征
    :param y: 预测值
    :return: 误差
    """
    y_pred = forward(x)
    return (y_pred - y) ** 2


#创建列表用于存放w值;损失值;偏执值
# w_list = []
mes_list = []
# b_list = []
W = np.arange(0.0, 4.1, 0.01)
B = np.arange(0.0, 4.1, 0.01)
[w, b] = np.meshgrid(W, B)


"""
#zip()函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。
"""
l_sum = 0
for x_val, y_val in zip(x_data, y_data):
    y_pred_val = forward(x_val)
    loss_val = loss(x_val, y_val)
    l_sum += loss_val
    # print(x_val, y_val, loss_val)
    # b_list.append(b)
# print('MSE:', l_sum / 3)
# w_list.append(w)
# mes_list.append(l_sum / 3)


#画图
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
surf = ax.plot_surface(w, b, l_sum/3)


plt.show()

第三节:梯度下降法

part1:

#加油加油加油
#认真对待每一行代码
#努力写好每一行代码
#搞懂每一行代码
import numpy as np
import matplotlib.pyplot as plt

x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]

w = 1.0


def forward(x):

    return x * w


def cost(xs, ys):
    """
    :param xs: 特征
    :param ys: 对应的真实值
    :return: 误差;返回的均方误差
    """
    cost = 0
    for x, y in zip(xs, ys):
        y_pred = forward(x)
        cost += (y_pred - y) ** 2

    return cost / len(xs)


def gradient(xs, ys):
    """
    求导(误差求导)
    :param xs: 特征
    :param ys: 对应的真实值
    :return: 返回的是均方误差的导数
    """
    grad = 0
    for x, y in zip(xs, ys):
        grad += 2 * x * (x * w - y)

    return grad / len(xs)


print('Predict (before traning)', 4, forward(4))

for epoch in range(100):
    """
    遍历100次
    调用cost函数计算损失值即误差值
    调用gradient函数求得求导值
    更新w值
    输出第几次迭代,对应的更新的权值,损失值
    """
    cost_val = cost(x_data, y_data)
    grad_val = gradient(x_data, y_data)
    w -= 0.01 * grad_val
    print('Epoch:', epoch, 'w = ', w, 'loss = ', cost_val)

print('Predict (after training)', 4, forward(4))

part2:

#加油加油加油
#认真对待每一行代码
#努力写好每一行代码
#搞懂每一行代码
import numpy as np
import matplotlib.pyplot as plt

x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]

w = 1.0


def forward(x):

    return x * w


def loss(x, y):

    y_pred = forward(x)
    return (y_pred - y) ** 2


def gradient(x, y):

    return 2 * x * (x * w - y)


"""
#第一次更新w前,使用w=1.0对特征为4时进行预测,返回预测值
#第二次,更新w后,使用更新后的w,对特征为4时预测,返回预测值
"""
print('Predict (before traning)', 4, forward(4))

for epoch in range(100):
    for x, y in zip(x_data, y_data):
        """
        求梯度
        更新w
        输出特征和对应的真实标签;
        计算损失
        输出w和loss
        """
        grad = gradient(x, y)
        w -= 0.01 * grad
        print('\tgrad:', x, y, grad)
        l = loss(x, y)
        print('progress:', epoch, 'w = ', w, 'loss = ', l)

print('Predict (after training)', 4, forward(4))

第四节:反向传播

part1:

#加油加油加油
#认真对待每一行代码
#努力写好每一行代码
#搞懂每一行代码
import torch

x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]

w = torch.Tensor([1.0])
w.requires_grad = True

"""
因为torch.Tensor函数,所以我们的w是一个张量;
下面我们计算时,返回的也是张量;这样就可以有一其他功能,便可直接函数取出我们想要的值;
item()是从原来的精度上更加精确;
最外的两个print分别是,模型跑之前,和w值改变之后再跑的预测结果。
"""


def forward(x):

    return x * w


def loss(x, y):
    """
    :param x: 输入特征
    :param y: 真实值
    :return: 损失值即误差
    """
    y_pred = forward(x)

    return (y_pred - y) ** 2


print("predict (before training)", 4, forward(4).item())

for epoch in range(100):
    for x, y in zip(x_data, y_data):
        """
        调用loss函数,求损失函数
        l.backward()--反向传播函数,自动会计算并且w的值也会做相应的更新,并且最终会释放掉数据
        这个函数作用就是用于做反向循环--这个时候w的值会有两个:w.data--w的值、w.grad--梯度值即对误差求导的值;
        更新w.data
        w.grad清零,即释放,用于下次计算
        """
        l = loss(x, y)
        l.backward()
        print('\tgrad:', x, y, w.grad.item(), w.data)
        w.data = w.data - 0.01 * w.grad.data
        print(w.data)
        w.grad.data.zero_()
        print(w.data, w.grad.item())

    print('progress:', epoch, l.item())

print('predict (after taining)', 4, forward(4).item())

第五节:用PyTorch实现线性回归

part1:

#加油加油加油
#认真对待每一行代码
#努力写好每一行代码
#搞懂每一行代码
import torch

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


class LinearModel(torch.nn.Module):
    """
    模型继承:linear模型
    linear(1, 1)是特征和输出的维度为一维
    forward:构建模型中的各个层的关系---也是输出怎么到输出的,用到哪些层;---可以调用__init__里的函数
    __init__:通多调用nn.Module中函数进行搭建每一层所用到的函数,函数的参数
    forward:将__init__中的搭建好的函数连通起来,告诉我们怎么连通,叙述整个流程
    """
    def __init__(self):
        super(LinearModel, self).__init__()
        self.linear = torch.nn.Linear(1, 1)     # w, b

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

        return y_pred


"""
模型的实例化
调用损失函数--criterion
选择优化器,学习率设置为0.01;同时其他的值通过model.parameters()函数进行初始化。
里面自己有各种参数,权重 偏置
"""
model = LinearModel()
criterion = torch.nn.MSELoss(size_average=False)
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)

for epoch in range(1000):
    """
    迭代1000次;
    模型传入特征值--返回预测值y_pred
    往损失函数-criterion-中传入预测值和真实值--返回损失值loss
    输出 当前迭代次数 + 当前损失值
    通过zero_grad函数将梯度值(即损失函数的导数)设置为0
    .backward进行反向传播
    optimizer.step()进行权值w和偏置b的迭代
    """
    y_pred = model(x_data)
    loss = criterion(y_pred, y_data)
    print(epoch, loss.item())
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

"""
输出最后的权值w
输出最后的偏置b
设置测试集数据
将测试集放入模型中进行预测
通过.data 输出预测数据
"""
print('w = ', model.linear.weight.item())
print('b = ', model.linear.bias.item())

x_test = torch.Tensor([[4.0]])
y_test = model(x_test)
print('y_pred = ', y_test.data)

第六节:逻辑回归

part1:

#加油加油加油
#认真对待每一行代码
#努力写好每一行代码
#搞懂每一行代码
import torch
import torch.nn.functional as F
import numpy as np
import matplotlib.pyplot as plt

x_data = torch.Tensor([[1.0], [2.0], [3.0]])
y_data = torch.Tensor([[0], [0], [1]])


class LogisticRegressionModel(torch.nn.Module):
    """
    继承nn.Module中的逻辑回归函数类
    linear(1, 1)--特征和标签都是一维数据
    """
    def __init__(self):
        super(LogisticRegressionModel, self).__init__()
        self.linear = torch.nn.Linear(1, 1)

    def forward(self, x):
        """
        先通过linear函数进行求得预测值
        然后通过调用F(torch.nn.functional)包中的sigmoid函数对预测结果达到分类效果
        :param x:特征
        :return: 分类标准(0, 1)用到的是sigmoid函数
        """
        y_pred = F.sigmoid(self.linear(x))
        return y_pred


"""
模型实例化
调用函数使用BCELoss求损失,并传给criterion
对模型参数w和b进行初始化;学习率设置为0.01
"""
model = LogisticRegressionModel()
criterion = torch.nn.BCELoss(size_average=False)
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)

for epoch in range(1000):
    """
    遍历1000次
    将数据存入模型返回预测值y_pred
    使用函数criterion,并传入预测值和对应的真实值;求得损失函数
    输出 当前迭代次数 和 损失值的高精度数据
    
    优化器的梯度赋值为0  即损失函数的导数
    通过backward函数进行反向传播
    使用optimizer.step()函数进行更新权值和偏置
    """
    y_pred = model(x_data)
    loss = criterion(y_pred, y_data)
    print(epoch, loss.item())

    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

"""
取0-10中200个点 赋值给x
将数组x变成张量  -- x_t
将张量x_t放入模型,得到预测张量y_t
利用y_t.data函数,取出预测值,变成数组形式 返回给y
画图传入参数x,y  (两个数据都是数组类型,并且长度是一样的)
画一条平行于x轴的红线。即[0, 10], [0.5, 0.5], c='r'
输出图像plot.show()
"""
x = np.linspace(0, 10, 200)
x_t = torch.Tensor(x).view((200, 1))
y_t = model(x_t)
y = y_t.data.numpy()
plt.plot(x, y)
plt.plot([0, 10], [0.5, 0.5], c='r')
plt.xlabel('Hours')
plt.ylabel('Probability of Pass')
plt.grid()
plt.show()

第七节:处理多维特征的输入

part1:

#加油加油加油
#认真对待每一行代码
#努力写好每一行代码
#搞懂每一行代码
import numpy as np
import matplotlib.pyplot as py
import torch

"""
读取文件,以逗号未分割点
取所有行,和第一列到倒数第二列
取所有行,和最后一列
"""
xy = np.loadtxt('diabetes.csv', delimiter=',', dtype=np.float32)
x_data = torch.from_numpy(xy[:, :-1])
y_data = torch.from_numpy(xy[:, [-1]])


class Model(torch.nn.Module):
    """
    super继承Module库
    线性变换;
    8维指的是8个特征-6维是6个特征;8个权重-6个权重
    这是线性网络
    输入数据为8维-输出6维
    输入数据为6维-输出4维
    输入数据为4维-输出1维
    调用sigmoid函数,对数据判断
    """
    def __init__(self):
        super(Model, self).__init__()
        self.linear1 = torch.nn.Linear(8, 6)
        self.linear2 = torch.nn.Linear(6, 4)
        self.linear3 = torch.nn.Linear(4, 1)
        self.sigmoid = torch.nn.Sigmoid()

    def forward(self, x):
        """
        :param x:输入数据
        :return:预测值
        """
        x = self.sigmoid(self.linear1(x))
        x = self.sigmoid(self.linear2(x))
        x = self.sigmoid(self.linear3(x))
        return x


"""
模型实例化
调用BCELoss函数--给criterion函数
使用SGD优化器,模型参数初始化(parameters()),学习率为0.01
"""
model = Model()
criterion = torch.nn.BCELoss(size_average=False)
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)

for epoch in range(100):
    """
    遍历100次
    将特征值传入模型,返回预测值(张量)
    传入预测和真实值,通过criterion函数,返回损失函数
    输出  当前次数  和  损失函数的高精度
    优化器中梯度值 参数归零
    反向传播
    通过优化器函数,optimizer.step函数进行更新权值w和偏置b,以及梯度值
    """
    y_pred = model(x_data)
    loss = criterion(y_pred, y_data)
    print(epoch, loss.item())
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

第八节:加载数据集

part1:

#加油加油加油
#认真对待每一行代码
#努力写好每一行代码
#搞懂每一行代码
import numpy as np
import torch
from torch.utils.data import Dataset, DataLoader


class DiabetesDataset(Dataset):
    """
    DiabetesDataset类继承Dataset类
    重写__init__方法:
    文件读取,传给xy
    去xy的shape[0],即取数据的数量,也即有多少行
    通过torch模块中的from_numpy函数进行数据的读取操作
    返回的  x_data  y_data 都是张量
    重写__getitem__方法:
    返回x_data的索引 和 y_data的索引
    重写__len__方法:
    返回数据第一位的数值
    """
    def __init__(self, filepath):
        xy = np.loadtxt(filepath, delimiter=',', dtype=np.float32)
        self.len = xy.shape[0]
        self.x_data = torch.from_numpy(xy[:, :-1])
        self.y_data = torch.from_numpy(xy[:, [-1]])

    def __getitem__(self, index):
        return self.x_data[index], self.y_data[index]

    def __len__(self):
        return self.len


"""
读取文件diabetes文件;返回dataset
通过DataLoader函数,传入参数:数据集,单词训练的样本数量;是否打乱数据集,多线程工作
"""
dataset = DiabetesDataset('diabetes.csv')
train_loader = DataLoader(dataset=dataset,
                          batch_size=32,
                          shuffle=True,
                          num_workers=2)


class Model(torch.nn.Module):
    """
    继承Module类,
    搭建不同层数中权值参数维度的变化。
    搭建一个sigmoid函数
    都是用torch库中封装好的函数
    """
    def __init__(self):
        super(Model, self).__init__()
        self.linear1 = torch.nn.Linear(8, 6)
        self.linear2 = torch.nn.Linear(6, 4)
        self.linear3 = torch.nn.Linear(4, 1)
        self.sigmoid = torch.nn.Sigmoid()

    def forward(self, x):
        """
        :param x: 特征
        :return: 预测数据
        """
        x = self.sigmoid(self.linear1(x))
        x = self.sigmoid(self.linear2(x))
        x = self.sigmoid(self.linear3(x))
        return x


"""
模型实例化--model
调用BCELoss损失函数
选择SGD优化器,其中初始化模型参数,学习率设置为0.01
"""
model = Model()
criterion = torch.nn.BCELoss(size_average=True)
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)

if __name__ == '__main__':
    for epoch in range(100):
        for i, data in enumerate(train_loader, 0):
            """
            i:第几次循环;
            data:【张量每个数据集,张量每个数据对应的标签】
            张量每个数据集:一个列表,batch个元素;每个元素是由一条数据中的特征所构成的列表。
            张量每个数据对应的标签:一个列表,batch个元素,每个元素是由数据中的标签构成的列表。
            [tensor([[], [], []]), tensor([[], [], []])]
            """
            # print("i", i)
            # print("data", data)
            inputs, labels = data
            """
            传出列表中的两个元素,都是张量
            inputs:tensor([[], [], []])
            labels:tensor([[], [], []])
            """
            # print("inputs", inputs)
            # print("labels", labels)
            """
            将数据集传入模型,得到预测值的张量形式
            通过criterion函数返回损失值--loss-张量
            输出:第几次循环所有数据集,当前循环下,训练的第几组(一个batch长度为一组)的数据集,和相应的损失值的高精度格式
            梯度值清零
            反向传播
            利用优化器进行参数更新
            """
            y_pred = model(inputs)
            loss = criterion(y_pred, labels)
            print(epoch, i, loss.item())
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()

part2:

#加油加油加油
#认真对待每一行代码
#努力写好每一行代码
#搞懂每一行代码
import torch
from torch.utils.data import DataLoader
from torchvision import transforms
from torchvision import datasets

train_dataset = datasets.MNIST(root='../dataset/mnist',
                               train=True,
                               transform=transforms.ToTensor(),
                               download=True)

test_dataset = datasets.MNIST(root='../dataset/mnist',
                              train=False,
                              transform=transforms.ToTensor(),
                              download=True)

train_loader = DataLoader(dataset=train_dataset,
                          batch_size=32,
                          shuffle=True)

test_loader = DataLoader(dataset=test_dataset,
                         batch_size=32,
                         shuffle=False)

for batch_idx, (inputs, target) in enumerate(train_loader):

    pass

第九节:多分类问题

part1:

#加油加油加油
#认真对待每一行代码
#努力写好每一行代码
#搞懂每一行代码
import numpy as np

y = np.array([1, 0, 0])
z = np.array([0.2, 0.1, -0.1])
y_pred = np.exp(z) / np.exp(z).sum()
loss = (-y * np.log(y_pred)).sum()
print(loss)
"""
这个是实现:我们给出真实的标签,和我们最后的输出层的数据;然后我们通过后softmax函数进行变换
softmax函数:e的x次方除以e的x次方的和,这个时候我们就可以保证每一个值是可以实现总和等于1的
同时我们就可以计算损失函数 -[ylog(y_^) + (1 - y)log(1 - y_^)]
我们可以直接写成 -ylog(y_^)
"""

part2:

#加油加油加油
#认真对待每一行代码
#努力写好每一行代码
#搞懂每一行代码
import torch

y = torch.LongTensor([0])
z = torch.Tensor([[0.2, 0.1, -0.1]])
criterion = torch.nn.CrossEntropyLoss()
loss = criterion(z, y)
print(loss)

"""
Torch.nn.CrossEntropyLoss()
交叉验证熵求解
torch直接封装好了,我们直接用,但是我们需要把数据改为张量(tensor)
封装的包括:softmax 函数:(各个数据的:e^x / sum(e^x)); 然后进行log变换,同时进行 loss函数(-ylogy_^)的求解
把后面的步骤都写出来了
所以我们的数据只需计算到最后一层,不需要进行softmax计算就好,
"""

part3:

#加油加油加油
#认真对待每一行代码
#努力写好每一行代码
#搞懂每一行代码
import torch

criterion = torch.nn.CrossEntropyLoss()
Y = torch.LongTensor([2, 0, 1])

Y_pred1 = torch.Tensor([[0.1, 0.2, 0.9],
                        [1.1, 0.1, 0.2],
                        [0.2, 2.1, 0.1]])
Y_pred2 = torch.Tensor([[0.8, 0.2, 0.3],
                        [0.2, 0.3, 0.5],
                        [0.2, 0.2, 0.5]])

l1 = criterion(Y_pred1, Y)
l2 = criterion(Y_pred2, Y)
print("Batch Loss1 = ", l1.data, "\nBatch Loss2 = ", l2.data)

"""
两组数据我们通过【2, 0, 1】进行比较预测两组数据那个损失函数比较低
"""

part4:

#加油加油加油
#认真对待每一行代码
#努力写好每一行代码
#搞懂每一行代码
import torch
from torchvision import transforms
from torchvision import datasets
from torch.utils.data import DataLoader
import torch.nn.functional as F
import torch.optim as optim


"""
一次性组合64个数据为一个数据

对数据进行下载;
shuffle(数据是否打乱)
对数据进行打乱---在进行batch分割---train_dataset--train_loader
对数据直接进行分割 --- test_dataset--test_loader
"""
batch_size = 64
transform = transforms.Compose([transforms.ToTensor(),
                                transforms.Normalize((0.1307, ), (0.3081, ))
                                ])

train_dataset = datasets.MNIST(root='../dataset/mnist/',
                               train=True,
                               download=True,
                               transform=transform)
train_loader = DataLoader(train_dataset,
                          shuffle=True,
                          batch_size=batch_size)

test_dataset = datasets.MNIST(root='../dataset/mnist/',
                              train=False,
                              download=True,
                              transform=transform)
test_loader = DataLoader(test_dataset,
                         shuffle=False,
                         batch_size=batch_size)


class Net(torch.nn.Module):
    """
    继承Module类,重写__init__和forward方法‘
    继承Net类
    书写神经网络层:(线性层)
    forward函数书写每一层的连接状态,进行的什么变化
    """
    def __init__(self):
        super(Net, self).__init__()
        self.l1 = torch.nn.Linear(784, 512)
        self.l2 = torch.nn.Linear(512, 256)
        self.l3 = torch.nn.Linear(256, 128)
        self.l4 = torch.nn.Linear(128, 64)
        self.l5 = torch.nn.Linear(64, 10)

    def forward(self, x):
        x = x.view(-1, 784)
        x = F.relu(self.l1(x))
        x = F.relu(self.l2(x))
        x = F.relu(self.l3(x))
        x = F.relu(self.l4(x))
        return self.l5(x)


"""
类的实例化--model
判断使用gpu还是cpu
模型传到gpu上(.to(device))
调用损失函数--criterion
选用优化器SGD 模型的数值初始化(权值,偏置,梯度函数等等),学习率设置为0.01, 
一般,神经网络在更新权值时,采用如下公式:

                                                   w = w - learning_rate * dw

    引入momentum后,采用如下公式:

                                                   v = mu * v - learning_rate * dw

                                                   w = w + v

    其中,v初始化为0,mu是设定的一个超变量,最常见的设定值是0.9。可以这样理解上式:如果上次的momentum()与这次的
"""
model = Net()
# model = model.cuda()
device = torch.device("cuda:0"if torch.cuda.is_available() else"cpu")
model.to(device)

criterion = torch.nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)


def train(epoch):
    """
    损失为0.0
    :param epoch: 迭代次数
    :return: 训练模型
    """
    running_loss = 0.0
    for batch_idx, data in enumerate(train_loader, 0):
        """
        取一个batch数据的索引值和相应的数据
        data = 特征数据 + 标签
        将数据上传到gpu上
        优化器将梯度设置为0
        将特征放入模型
        利用criterion函数计算损失函数
        利用.backward函数进行反向传播
        利用优化器进行更新权值和偏置值,更新的效果
        将损失函数的高精度进行叠加,传给running_loss变量
        判断对所有数据进行的第几组batch,如果是300组则输出....
        并且running损失为0
        """

        inputs, target = data
        # inputs.cuda()
        # target.cuda()
        inputs, target = inputs.to(device), target.to(device)
        optimizer.zero_grad()

        outputs = model(inputs)
        loss = criterion(outputs, target)
        loss.backward()
        optimizer.step()

        running_loss += loss.item()
        if batch_idx % 300 == 299:
            print('[%d, %5d] loss: %.3f' % (epoch + 1, batch_idx + 1, running_loss / 300))
            running_loss = 0.0


def test():
    """
    :return:预测结果
    定义两个变量
    """
    correct = 0
    total = 0
    with torch.no_grad():
        for data in test_loader:
            """
            取出测试数据
            将特征传给-images;标签传给-labels
            将数据放在gpu上
            将特征数据放入模型
            torch.max的返回值有两个,第一个是每一行的最大值是多少,第二个是每一行最大值的下标(索引)是多少。
            # dim = 1 列是第0个维度,行是第1个维度
               ---返回标签---
            如果预测值和标签一样,则加一
            total = 数据量
            # 张量之间的比较运算
            正确数据量除以总数据量  乘以  100 得到百分比
            """
            images, labels = data
            # images.cuda()
            # labels.cuda()
            images, labels = images.to(device), labels.to(device)
            outputs = model(images)
            _, predicted = torch.max(outputs.data, dim=1)
            total += labels.size(0)
            correct += (predicted == labels).sum().item()

    print('Accuracy on test set: %d %%' % (100 * correct / total))


if __name__ == '__main__':
    for epoch in range(10):
        train(epoch)
        test()

第十节:卷积神经网络(基础篇)(CNN)

part1:

#加油加油加油
#认真对待每一行代码
#努力写好每一行代码
#搞懂每一行代码
import torch

in_channels, out_channels = 5, 10
width, height = 100, 100
kernel_size = 3
batch_size = 1

"""
通道---可以想想成厚度
输入数据的设置:
batch_size = 一次集合多少数据
输入通道数
数据平面的维度,宽和高

构建卷积层:
利用卷积核进行卷积操作:nn.Conv2d :
输入通道,输出通道 卷积核的大小,就卷积核的平面层;
"""
input = torch.randn(batch_size,
                    in_channels,
                    width,
                    height)

conv_layer = torch.nn.Conv2d(in_channels,
                             out_channels,
                             kernel_size=kernel_size)

output = conv_layer(input)

print(input.shape)
print(output.shape)
print(conv_layer.weight.shape)

part2:

#加油加油加油
#认真对待每一行代码
#努力写好每一行代码
#搞懂每一行代码
import torch

input = [3, 4, 6, 5, 7,
         2, 4, 6, 8, 2,
         1, 6, 7, 8, 4,
         9, 7, 4, 6, 2,
         3, 7, 5, 4, 1]

"""
(1, 1, 5, 5)--- batch, 通道, width,height
卷积核:输入通道, 输出通道, 卷积核3*3, padding = 1, 不设置偏置
重写卷积核参数
数据训练
"""
input = torch.Tensor(input).view(1, 1, 5, 5)

conv_layer = torch.nn.Conv2d(1, 1, kernel_size=3, padding=1, bias=False)

kernel = torch.Tensor([1, 2, 3, 4, 5, 6, 7, 8, 9]).view(1, 1, 3, 3)
conv_layer.weight.data = kernel.data

output = conv_layer(input)
print(output)

part3:

#加油加油加油
#认真对待每一行代码
#努力写好每一行代码
#搞懂每一行代码
import torch

"""
数据转换:batch,channel,width,height
卷积核2*2,MaxPool2d函数
搭建模型
"""
input = [3, 4, 6, 5,
         2, 4, 6, 8,
         1, 6, 7, 8,
         9, 7, 4, 6,
         ]
input = torch.Tensor(input).view(1, 1, 4, 4)

maxpooling_layer = torch.nn.MaxPool2d(kernel_size=2)

output = maxpooling_layer(input)
print(output)

part4:

#加油加油加油
#认真对待每一行代码
#努力写好每一行代码
#搞懂每一行代码
import torch
from torchvision import transforms
from torchvision import datasets
from torch.utils.data import DataLoader
import torch.nn.functional as F
import torch.optim as optim

"""
batch=64;
数据转换函数--变张量
下载数据,取出训练数据,dataset.MNIST函数
数据打断设置batch,DataLoader
下载数据,取出测试数据,dataset.MNIST函数
数据不打断 设置batch
"""
batch_size = 64
transform = transforms.Compose([transforms.ToTensor(),
                                transforms.Normalize((0.1307, ), (0.3081, ))
                                ])

train_dataset = datasets.MNIST(root='../dataset/mnist',
                               train=True,
                               download=True,
                               transform=transform)
train_loader = DataLoader(train_dataset,
                          shuffle=True,
                          batch_size=batch_size)

test_dataset = datasets.MNIST(root='../dataset/mnist',
                              train=False,
                              download=True,
                              transform=transform)
test_loader = DataLoader(test_dataset,
                         shuffle=False,
                         batch_size=batch_size)


class Net(torch.nn.Module):
    def __init__(self):
        """
        搭建连接层
        Conv2d(输入通道,输出通道,卷积核是 几乘几的)
        MaxPool2d(2)   池化层   除以二;x y 维度上
        Linear线性变换
        """
        super(Net, self).__init__()
        self.conv1 = torch.nn.Conv2d(1, 10, kernel_size=5)
        self.conv2 = torch.nn.Conv2d(10, 20, kernel_size=5)
        self.pooling = torch.nn.MaxPool2d(2)
        self.fc = torch.nn.Linear(320, 10)

    def forward(self, x):
        """
        #Flatten data from (n, 1, 28, 28) to (n, 784)
        获取x的第一个参数,返回给batch,即获取batch的大小
        先通过 卷积核(conv1) 进行卷积变换 - 进行 池化层(pooling)  - 再 正则化(relu)
        通过(conv2)卷积核 进行卷积变换 - 进行 池化层(pooling) - 再 正则化(relu)
        将做变换好的数据,拉长,变成一个 一维的数据。 - view(batch, -1) 一次处理batch个数据
        进行线性变换 - Linear 函数
        :param x: 输入数据
        :return: 输出数据
        """
        batch_size = x.size(0)
        x = F.relu(self.pooling(self.conv1(x)))
        x = F.relu(self.pooling(self.conv2(x)))
        x = x.view(batch_size, -1)
        x = self.fc(x)
        return x


"""
实例化Net类
判断在GPU还是cpu上跑,这里是在gpu上
将模型放在gpu上(to.(device))
代价函数
优化器,初始化模型参数(权重,偏置),学习率0.01, 为了防止局部最优,在进行迭代时,再加一个函数,这里设置为0.5,和学习率一个等级
"""
model = Net()
device = torch.device("cuda:0"if torch.cuda.is_available() else"cpu")
model.to(device)
criterion = torch.nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)


def train(epoch):
    running_loss = 0.0
    for batch_idx, data in enumerate(train_loader, 0):
        """
        train_loader 传出 batch的索引,即第几次数据, data当前数据
        将数据的特征和标签传给 inputs,和 target
        将数据传入gpu上
        优化器中的梯度设置为零
        将数据放入模型中
        criterion计算损失值
        .backward - 反向传播
        优化器函数进行更新权重
        将损失值进行累加 传给 running_loss函数
        输出第300次及300的倍数次的测试数据  --  第几次迭代, 当前的第几组数据,即第几个batch,当前损失和
        每300次,损失值做一个归结
        """
        inputs, target = data
        inputs, target = inputs.to(device), target.to(device)
        optimizer.zero_grad()
        # forward + backward + update
        outputs = model(inputs)
        loss = criterion(outputs, target)
        loss.backward()
        optimizer.step()

        running_loss += loss.item()
        if batch_idx % 300 == 299:
            print('[%d, %5d] loss: %.3f' % (epoch + 1, batch_idx + 1, running_loss / 2000))
            running_loss = 0.0


def test():
    correct = 0
    total = 0
    with torch.no_grad():
        """
        torch.no_grad()不用计算梯度
        对测试数据进行遍历
        将数据的 特征和标签 分别传给 images和labels
        数据传到gpu上
        带入模型进行预测 得到预测结果 - outputs
        这里是,我们取出概率最大的那个数作为输出
        取出标签的第一列, 进行累加,即计算总的数据集长度
        判断正确的数量,进行累加
        输出正确率
        """
        for data in test_loader:
            images, labels = data
            images, labels = images.to(device), labels.to(device)
            outputs = model(images)
            _, predicted = torch.max(outputs.data, dim=1)
            total += labels.size(0)
            correct += (predicted == labels).sum().item()

    print('Accuracy on test set: %d %%' % (100 * correct / total))


if __name__ == '__main__':
    for epoch in range(10):
        train(epoch)
        test()

第十一节:卷积神经网络(高级篇)(CNN)

part1:

#加油加油加油
#认真对待每一行代码
#努力写好每一行代码
#搞懂每一行代码
"""
构建数据处理函数 - 取出数据 - 进行数据处理(训练,测试)
搭建晓得模块的模型
再搭建整个模型 - 传入小模型,共同构建新的模型
实例化模型 - 选择损失函数,优化器
传入训练集对模型进行训练,传入测试集进行测试
写主函数
"""
import torch

from torchvision import transforms
from torchvision import datasets
from torch.utils.data import DataLoader

import torch.nn.functional as F
import torch.optim as optim
import torch.nn as nn

"""
设置batch
调用数据转换函数,transform函数
取出训练集,达到训练数据 - train_dataset
将训练集用DataLoader函数进行处理, shuffle数据打乱,batch个数据合成一个数据
测试集同样操作,只是没有打乱数据的操作
"""
batch_size = 64
transform = transforms.Compose([transforms.ToTensor(),
                                transforms.Normalize((0.1307, ), (0.3081, ))
                                ])

train_dataset = datasets.MNIST(root='../dataset/mnist',
                               train=True,
                               download=True,
                               transform=transform)
train_loader = DataLoader(train_dataset,
                          shuffle=True,
                          batch_size=batch_size)

test_dataset = datasets.MNIST(root='../dataset/mnist',
                              train=False,
                              download=True,
                              transform=transform)
test_loader = DataLoader(test_dataset,
                         shuffle=False,
                         batch_size=batch_size)


class InceptionA(nn.Module):
    def __init__(self, in_channels):
        """
        Inception类---继承Module类,
        重新写__init__ forward  方法
        搭建
        卷积层:branch1*1 = Conv2d(输入通达数,输出通道数,卷积核1*1)
        卷积层:branch5*5_1 = Conv2d(输入通道数,输出通道数,卷积核1*1)
        卷积层:branch5*5_2 = Conv2d(输入通道数,输出通道数,卷积核5*5,步长padding=2)
        卷积层:branch3*3_1 = Conv2d(输入通道数,输出通道数,卷积核1*1)
        卷积层:branch3*3_2 = Conv2d(输入通道数,输出通道数,卷积核3*3,步长padding=1)
        卷积层:branch3*3_3 = Conv2d(输入通道数,输出通道数,卷积核3*3,步长padding=1)
        卷积层:branch_pool = Conv2d(输入通道数,输出通道数,卷积核3*3,步长padding=1)
        :param in_channels: 输入通道数,即输出数据的通道数(厚度)
        """
        super(InceptionA, self).__init__()
        self.branch1x1 = nn.Conv2d(in_channels, 16, kernel_size=1)

        self.branch5x5_1 = nn.Conv2d(in_channels, 16, kernel_size=1)
        self.branch5x5_2 = nn.Conv2d(16, 24, kernel_size=5, padding=2)

        self.branch3x3_1 = nn.Conv2d(in_channels, 16, kernel_size=1)
        self.branch3x3_2 = nn.Conv2d(16, 24, kernel_size=3, padding=1)
        self.branch3x3_3 = nn.Conv2d(24, 24, kernel_size=3, padding=1)

        self.branch_pool = nn.Conv2d(in_channels, 24, kernel_size=1)

    def forward(self, x):
        """
        1、将数据用branch1*1进行处理--branch1*1
        2、将数据用branch5*5_1进行处理,再将处理过的数据放进branch5*5_2卷积层进行训练--branch5*5_2
        3、将数据用branch3x3_1进行处理,再将处理过的数据放进branch3x3_2卷积层进行训练得到新的数据,再讲这些数据放入branch3x3_3层得到__branch3x3
        4、将数据用avg_pool2d进行卷积操作,再将得到的数据放进branch_pool卷积进行训练得到--branch_pool
        将得到的四组数据进行整合--outputs
        # b,c,w,h  c对应的是dim=1,通道数
        :param x:输入数据
        :return:训练后的通道数
        """
        branch1x1 = self.branch1x1(x)

        branch5x5 = self.branch5x5_1(x)
        branch5x5 = self.branch5x5_2(branch5x5)

        branch3x3 = self.branch3x3_1(x)
        branch3x3 = self.branch3x3_2(branch3x3)
        branch3x3 = self.branch3x3_3(branch3x3)

        branch_pool = F.avg_pool2d(x, kernel_size=3, stride=1, padding=1)
        branch_pool = self.branch_pool(branch_pool)

        outputs = [branch1x1, branch5x5, branch3x3, branch_pool]

        return torch.cat(outputs, dim=1)


class Net(nn.Module):
    def __init__(self):
        """
        Net继承Module类
        重写__init__ 和 forward 方法
        搭建
        卷积层:Conv2d(输入通道,输出通道,卷积核大小)--conv1
        卷积层:Conv2d(输入通道,输出通道,卷积核大小)--conv2
        调用Inception方法--incep1
        调用Inception方法--incep2
        池化层 MaxPool2d函数--mp
        搭建线性层Linear(输入数据维度,输出维度)--fc
        """
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(1, 10, kernel_size=5)
        self.conv2 = nn.Conv2d(88, 20, kernel_size=5)

        self.incep1 = InceptionA(in_channels=10)
        self.incep2 = InceptionA(in_channels=20)

        self.mp = nn.MaxPool2d(2)
        self.fc = nn.Linear(1408, 10)

    def forward(self, x):
        """
        取出x的size的第一位,获取batch的大小,这里可以根据模型实例化后,看传入的参数是什么,这里取得是参数的size 的 第一个数据,这里是一个数据有多少数据组成的
        x - 卷积层conv1 - 进行池化mp - 正则化relu(调用的F中的relu函数)- x
        将得到的x - 放入incep1中得到新的 - x
        x - 卷积层conv2 - 进行池化mp - 正则化relu(调用的F中的relu函数)- x
        将得到的x - 放入incep2中得到新的 - x
        将x用.view函数将二维数据转化成一维数据
        记性线性变换
        :param x:输入数据
        :return:返回结果
        """
        in_size = x.size(0)
        x = F.relu(self.mp(self.conv1(x)))
        x = self.incep1(x)
        x = F.relu(self.mp(self.conv2(x)))
        x = self.incep2(x)
        x = x.view(in_size, -1)
        x = self.fc(x)

        return x


"""
实例化类 - model
判断是在什么上运行gpu or cpu
将模型放在GPU上
调用损失函数--criterion
悬着SGD优化器,模型参数初始化(权重,偏置,.parameters), 学习率0.01,momentum = 0.5,更好的进行求最小值,减少局部最优
"""
model = Net()
device = torch.device("cuda:0"if torch.cuda.is_available() else"cpu")
model.to(device)
criterion = torch.nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)


def train(epoch):
    running_loss = 0.0
    for batch_idx, data in enumerate(train_loader, 0):
        """
        取出训练数据 - 第几个数据, 输入数据
        将数据取出特征和标签 - inputs, target
        将数据放入gpu上
        优化器的梯度设置为0
        将数据的特征放入模型,进行训练
        计算损失函数 - loss
        反向传播, - .backward
        优化器函数进行梯度迭代,更新权重和偏置
        损失累加 - running_loss
        每300个数据进行输出一次(第几次迭代,第几个数据,损失是多少)
        并且损失running_loss置零
        """
        inputs, target = data
        inputs, target = inputs.to(device), target.to(device)
        optimizer.zero_grad()

        # forward + backward + update
        outputs = model(inputs)
        loss = criterion(outputs, target)
        loss.backward()
        optimizer.step()

        running_loss += loss.item()
        if batch_idx % 300 == 299:
            print('[%d, %5d] loss: %.3f' % (epoch + 1, batch_idx + 1, running_loss / 2000))
            running_loss = 0.0


def test():
    correct = 0
    total = 0
    with torch.no_grad():
        """
        不用计算梯度
        遍历测试集
        将数据的 特征和标签 传给 - images labels
        将数据放在GPU上
        将特征放入模型进行训练 - outputs
        取出结果的最大值, max
        计算标签的长度,即计算测试了多少数量 通过累加 返回给 - total
        计算预测正确的函数进行累加 - correct
        输出正确率
        """
        for data in test_loader:
            images, labels = data
            images, labels = images.to(device), labels.to(device)
            outputs = model(images)
            _, predicted = torch.max(outputs.data, dim=1)
            total += labels.size(0)
            correct += (predicted == labels).sum().item()

    print('Accuracy on test set: %d %%' % (100 * correct / total))


if __name__ == '__main__':
    for epoch in range(10):
        train(epoch)
        test()

part2:

#加油加油加油
#认真对待每一行代码
#努力写好每一行代码
#搞懂每一行代码
import torch

from torchvision import transforms
from torchvision import datasets
from torch.utils.data import DataLoader

import torch.nn.functional as F
import torch.optim as optim
import torch.nn as nn

batch_size = 64
transform = transforms.Compose([transforms.ToTensor(),
                                transforms.Normalize((0.1307, ), (0.3081, ))
                                ])

train_dataset = datasets.MNIST(root='../dataset/mnist',
                               train=True,
                               download=True,
                               transform=transform)
train_loader = DataLoader(train_dataset,
                          shuffle=True,
                          batch_size=batch_size)

test_dataset = datasets.MNIST(root='../dataset/mnist',
                              train=False,
                              download=True,
                              transform=transform)
test_loader = DataLoader(test_dataset,
                         shuffle=False,
                         batch_size=batch_size)


class ResidualBlock(nn.Module):
    def __init__(self, channels):
        super(ResidualBlock, self).__init__()
        self.channels = channels
        self.conv1 = nn.Conv2d(channels, channels,
                               kernel_size=3, padding=1)
        self.conv2 = nn.Conv2d(channels, channels,
                               kernel_size=3, padding=1)

    def forward(self, x):
        y = F.relu(self.conv1(x))
        y = self.conv2(y)

        return F.relu(x + y)


class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(1, 16, kernel_size=5)
        self.conv2 = nn.Conv2d(16, 32, kernel_size=5)
        self.mp = nn.MaxPool2d(2)

        self.rblock1 = ResidualBlock(16)
        self.rblock2 = ResidualBlock(32)

        self.fc = nn.Linear(512, 10)

    def forward(self, x):
        in_size = x.size(0)
        x = self.mp(F.relu(self.conv1(x)))
        x = self.rblock1(x)
        x = self.mp(F.relu(self.conv2(x)))
        x = self.rblock2(x)
        x = x.view(in_size, -1)
        x = self.fc(x)

        return x


model = Net()
device = torch.device("cuda:0"if torch.cuda.is_available() else"cpu")
model.to(device)
criterion = torch.nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)

def train(epoch):
    running_loss = 0.0
    for batch_idx, data in enumerate(train_loader, 0):
        inputs, target = data
        inputs, target = inputs.to(device), target.to(device)
        optimizer.zero_grad()

        #forward + bakward + iupdata
        outputs = model(inputs)
        loss = criterion(outputs, target)
        loss.backward()
        optimizer.step()

        running_loss += loss.item()
        if batch_idx % 300 == 299:
            print('[%d, %5d] loss: %.3f' % (epoch + 1, batch_idx + 1, running_loss / 2000))
            running_loss = 0.0


def test():
    correct = 0
    total = 0
    with torch.no_grad():
        for data in test_loader:
            images, labels = data
            images, labels = images.to(device), labels.to(device)
            outputs = model(images)
            _, predicted = torch.max(outputs.data, dim=1)
            total += labels.size(0)
            correct += (predicted == labels).sum().item()

    print('Accuracy on test set: %d %%' % (100 * correct / total))


if __name__ == '__main__':
    for epoch in range(10):
        train(epoch)
        test()

第十二节:循环神经网络(基础篇)(RNN)

part1:

#加油加油加油
#认真对待每一行代码
#努力写好每一行代码
#搞懂每一行代码
import torch

batch_size = 1
seq_len = 3
input_size = 4
hidden_size = 2

"""
单个RNN
即循环神经网络的单个部分
多个部分组成的是RNN
"""
cell = torch.nn.RNNCell(input_size=input_size, hidden_size=hidden_size)

#(seq, batch, features)
"""
生成标准正态分布的(均值为零,方差为一,的高斯白噪声)的随机数;
.randn生成(3,1,4)  --  张量
生成为全为0.的数,
.zeros生成(1,2)  --  张量
"""
dataset = torch.randn(seq_len, batch_size, input_size)
hidden = torch.zeros(batch_size, hidden_size)
print(dataset)

for idx, input in enumerate(dataset):
    """
    idx:第几次遍历
    input:取出当前次数的数据,数据维度是(1,4)
    cell(输入数据(batch,特征的向量维度),记忆体维度(batch,hidden的维度))
    """
    print('=' * 20, idx, '=' * 20)
    hidden = cell(input, hidden)
    print('outputs size: ', hidden.shape)
    print(hidden)

part2:

#加油加油加油
#认真对待每一行代码
#努力写好每一行代码
#搞懂每一行代码
import torch

batch_size = 1
seq_len = 3
input_size = 4
hidden_size = 2
num_layers = 1

"""
循环神经网络函数RNN
(输入数据(数据的时间维度x的个数,batch,单个数据的维度),记忆体数据(层数(也即第几层的hidden),hidden的维度),层数)
"""
cell = torch.nn.RNN(input_size=input_size, hidden_size=hidden_size,
                    num_layers=num_layers)

#(seqLen, batchSize, inputSize)
inputs = torch.randn(seq_len, batch_size, input_size)
hidden = torch.zeros(num_layers, batch_size, hidden_size)

"""
输出数据:
out:(seq_len,batch,hidden数据维度)--最上边的那一行,横着的,也就是输出
hidden:(层数,batch,hidden数据维度)
"""
out, hidden = cell(inputs, hidden)
print('Output size: ', out.shape)
print('Output: ', out)
print('Hidden size: ', hidden.shape)
print('Hidden: ', hidden)

part3:

#加油加油加油
#认真对待每一行代码
#努力写好每一行代码
#搞懂每一行代码
import torch

batch_size = 1
# seq_len = 3
input_size = 4
hidden_size = 4
# num_layers = 1


"""
创建字典
设置输入数据中,每一个x的索引位置构成一个列表
同理。构建一个列表y
构建独热向量(one-hot)
利用for循环,搭建出每一个x对应的向量
-----
将搭建好的数据通过.view方法
构建张量
inputs(seq_len,batch,输入数据)(5,1,4)
label(seq_len,batch)
"""
idx2char = ['e', 'h', 'l', 'o']
x_data = [1, 0, 2, 2, 3]
y_data = [3, 1, 2, 3, 2]

one_hot_lookup = [[1, 0, 0, 0],
                  [0, 1, 0, 0],
                  [0, 0, 1, 0],
                  [0, 0, 0, 1]]
x_one_hot = [one_hot_lookup[x] for x in x_data]
inputs = torch.Tensor(x_one_hot).view(-1, batch_size, input_size)
labels = torch.LongTensor(y_data).view(-1, 1)


class Model(torch.nn.Module):
    def __init__(self, input_size, hidden_size, batch_size):
        """
        Model继承Module类
        重写__init__;forward;init_hidden方法
        init(输入数据维度,记忆体维度,batch)
        super超类
        调用torch..nn.RNNCell(输入数据的维度,记忆体的维度)函数
        :param input_size:(batch,输入数据)
        :param hidden_size:(batch,hidden数据)
        :param batch_size:(batch)
        """
        super(Model, self).__init__()
        #self.num_layers = num_layers
        self.batch_size = batch_size
        self.input_size = input_size
        self.hidden_size = hidden_size
        self.rnncell = torch.nn.RNNCell(input_size=self.input_size,
                                        hidden_size=self.hidden_size)

    def forward(self, input, hidden):
        """
        方法,直接使用RNNCell函数,进行训练
        :param input: (batch,inputs)
        :param hidden: (batch,hidden)
        :return: (out(batch,hidden))
        """
        hidden = self.rnncell(input, hidden)

        return hidden

    def init_hidden(self):
        """
        使用torch中的zeros函数,生成维度为(batch,hidden),数值为(0.)的张量
        :return:
        """

        return torch.zeros(self.batch_size, self.hidden_size)


"""
实例化Model类 -- net
使用CrossEntropyLoss函数计算损失 -- criterion
选择Adam优化器,初始化模型参数(W_hh,W_ih,B_ih,B_hh),学习率为0.1
"""
net = Model(input_size, hidden_size, batch_size)
criterion = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(net.parameters(), lr=0.1)

for epoch in range(15):
    """
    遍历15次
    损失值为更新为0
    梯度值为0
    取出训练集的特征和对应的标签 - 一次取一组,for循环来取
    将特征集填入模型,传出hidden-即输出值
    通过criterion函数计算损失值进行累加
    通过max函数取出,hidden中最大值,返回其索引位置 -- idx
    输出当前预测的结果
    
    反向传播
    优化器更新参数(权值,偏置,梯度)
    每次循环完,输出当前的循环的损失值
    """
    loss = 0
    optimizer.zero_grad()
    hidden = net.init_hidden()
    print('Predicted string: ', end='')
    for input, label in zip(inputs, labels):
        hidden = net(input, hidden)
        loss += criterion(hidden, label)
        _, idx = hidden.max(dim=1)
        print(idx2char[idx.item()], end='')

    loss.backward()
    optimizer.step()
    print(', Epoch [%d/15] loss = %.4f' % (epoch + 1, loss.item()))

part4:

#加油加油加油
#认真对待每一行代码
#努力写好每一行代码
#搞懂每一行代码
import torch

batch_size = 1
seq_len = 5
input_size = 4
hidden_size = 4
num_layers = 1

idx2char = ['e', 'h', 'l', 'o']
x_data = [1, 0, 2, 2, 3]
y_data = [3, 1, 2, 3, 2]

"""
inputs(seq_len 5,batch 1,input_size 4)
"""
one_hot_lookup = [[1, 0, 0, 0],
                  [0, 1, 0, 0],
                  [0, 0, 1, 0],
                  [0, 0, 0, 1]]
x_one_hot = [one_hot_lookup[x] for x in x_data]
inputs = torch.Tensor(x_one_hot).view(seq_len, batch_size, input_size)
labels = torch.LongTensor(y_data)


class Model(torch.nn.Module):
    def __init__(self, input_size, hidden_size, batch_size, num_layers=1):
        """
        继承Module类
        super超类
        重写__init__,forward方法
        调用RNN函数(输入数据维度,记忆层数据,层数)
        :param input_size:
        :param hidden_size:
        :param batch_size:
        :param num_layers:
        """
        super(Model, self).__init__()
        self.num_layers = num_layers
        self.batch_size = batch_size
        self.input_size = input_size
        self.hidden_size = hidden_size
        self.rnn = torch.nn.RNN(input_size=self.input_size,
                                hidden_size=self.hidden_size,
                                num_layers=num_layers)

    def forward(self, input):
        """
        创建记忆层的维度(hidden:层数,batch,hidden维度)
        out:最后一层的输出值(即预测值)--(seq_len,batch,input_size)
        _ :最后时刻的hidden的值 -- (num_layers,batch,hidden_size)
        :param input: 输入数据
        :return:seq_len,hidden_size(每个时间的数据都会有个out,我们将每一个out组合起来,
        out中的一个数据和hidden是一样的维度,因为out_1 = g(W_oh * hidden))相当于我们自己定义了out的维度
        """
        hidden = torch.zeros(self.num_layers,
                             self.batch_size,
                             self.hidden_size)
        out, _ = self.rnn(input, hidden)

        return out.view(-1, self.hidden_size)


"""
实例化类--net  参数:输入数据,记忆层数据,batch,层数
调用损失函数
选择Adam优化器,模型初始化(W_ih,W_hh,B_ih,B_hh)学习率为0.05
"""
net = Model(input_size, hidden_size, batch_size, num_layers)
criterion = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(net.parameters(), lr=0.05)

for epoch in range(15):
    """
    优化器函数的梯度设置为0
    将数据放入net模型中
    计算损失函数
    反向传播
    优化器更新权值,偏置,梯度等
    期初每一个数据的最大值的索引,
    一次输出索引值对应的字母
    输出 迭代次数和损失函数
    """
    # loss = 0
    optimizer.zero_grad()
    outputs = net(inputs)
    loss = criterion(outputs, labels)
    loss.backward()
    optimizer.step()
    _, idx = outputs.max(dim=1)
    idx = idx.data.numpy()
    print('Predicted: ', ''.join([idx2char[x] for x in idx]), end='')
    print(', Epoch [%d/15] loss = %.3f' % (epoch + 1, loss.item()))

part5:

#加油加油加油
#认真对待每一行代码
#努力写好每一行代码
#搞懂每一行代码

import torch

num_class = 4
batch_size = 1
seq_len = 5
input_size = 4
hidden_size = 8
num_layers = 2
embedding_size = 10

"""
创建字典,创建由特征索引构成的二维向量(1,5),和对应的标签对应字母索引所构成的(5)
将x_data y_data转换为张量  (1,5)(5)
"""
idx2char = ['e', 'h', 'l', 'o']
x_data = [[1, 0, 2, 2, 3]]
y_data = [3, 1, 2, 3, 2]
inputs = torch.LongTensor(x_data)
labels = torch.LongTensor(y_data)


class Model(torch.nn.Module):
    def __init__(self):
        """
        Model继承Module类
        super超类
        重写__init__,forward方法
        调用Embedding函数,(input_size,embedding_size)--将input_size变成embedding_size(4-10)每一个数据4维变成10维
        调用RNN函数(输入维度,记忆层维度,层数)batch_first=true则喂数据时为:input(batch_size,seq_len,hidden_size)
        batch_first=False则喂数据时为:input(seq_len,batch_size,hidden_size)
        Linear(hidden_size,类别数量)
        """
        super(Model, self).__init__()
        self.emb = torch.nn.Embedding(input_size, embedding_size)
        self.rnn = torch.nn.RNN(input_size=embedding_size,
                                hidden_size=hidden_size,
                                num_layers=num_layers,
                                batch_first=True)
        self.fc = torch.nn.Linear(hidden_size, num_class)

    def forward(self, x):
        """
        创建记忆体(全是0. 维度(层数,input_size(0) - 即batch_size),hidden_size)
        先对输入数据进行Embedding,嵌入层,将input_size  --  embedding_size;得到高维数据---(batch_size,seq_len,embedding_size)
        将得到的数据进行rnn模型进行训练(x(batch_size,seq_len,embedding_size),hidden(num_layers,batch,hidden_size))
        返回out最后一层的输出,和 hidden最后时刻的记忆体的参数
        out:(batch,seq_len,embedding)
        _ :(num_layer,batch_size, hidden_size)
        通过线性函数Linear。维度是num_class
        .view()展示的是将(out即x)的每一个值都组合起来,变成(seq_len,num_class)batch_size
        :param x: 输入数据input
        """
        hidden = torch.zeros(num_layers, x.size(0), hidden_size)
        x = self.emb(x)
        x, _ = self.rnn(x, hidden)
        x = self.fc(x)

        return x.view(-1, num_class)


"""
实例化类--net
调用损失函数--criterion
调用Adam优化器,初始化net模型中的参数(权重,偏置),学习率0.05
"""
net = Model()
criterion = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(net.parameters(), lr=0.05)

for epoch in range(15):
    """
    优化器的梯度设置为0
    将input放入模型,返回out的数据(是矩阵(seq_len,num_class))
    计算损失函数
    反向传播
    优化器迭代,更新参数(权重,偏置,梯度)
    通过max返回每一组数据的最大值对应的索引
    查找出字典对应索引的字母,输出
    输出当前迭代次数和损失值
    """
    # loss = 0
    optimizer.zero_grad()
    outputs = net(inputs)
    print(outputs.shape)
    loss = criterion(outputs, labels)
    loss.backward()
    optimizer.step()

    _, idx = outputs.max(dim=1)
    idx = idx.data.numpy()

    print('Predicted: ', ''.join([idx2char[x] for x in idx]), end='')
    print(', Epoch [%d/15] loss = %.3f' % (epoch + 1, loss.item()))

第十三节:循环神经网络(高级篇)(RNN)

part1:GRU

#加油加油加油
#认真对待每一行代码
#努力写好每一行代码
#搞懂每一行代码

import torch
from torch.utils.data import Dataset, DataLoader
from torch.nn.utils.rnn import pack_padded_sequence
import time
import matplotlib.pyplot as plt
import numpy as np
import gzip
import csv
import math

"""
hidden_size=100,batch_size=256,n_layer=2,n_epochs=100,n_chars=128,
记忆体维度100,batch维度为256,层数为2层,迭代次数100次,
"""
HIDDEN_SIZE = 100
BATCH_SIZE = 256
N_LAYER = 2
N_EPOCHS = 100
N_CHARS = 128
USE_GPU = True


class NameDataset(Dataset):
    """
    NameDataset类继承Dataset类
    重写__init__,__getitem__,__len__方法
    定义getCountryDict,idx2country,getCountriesNum函数
    实例化后,返回的有:
    countries:list,数据中的第二列即所有国家,无排序,无去重
    country_dict:dict:18,数据中所有国家,有排序,有去重,{键;键值}
    country_list:list:18,数据中所有国家,有排序,有去重
    country_num:int:18
    len:int,数据中名字的长度,即所有数据的数量
    names:list,数据所有名字,有排序
    """
    def __init__(self, is_train_set=True):
        """
        这个文件是第一列为名字,第二列为国家
        :param is_train_set: 用于判断文件类型
        使用gzip方法读取文件(解压读取)
            再用csv的方法将提取的文件读取,
            再用list方法将数据转换成列表 -- rows
        name = 取出rows列表中每个元素的第一个值;即文件的第一列 -- 名字
        len = 多少个名字
        counties = 取出rows列表中每个元素的第二个值,即文件的第二列 -- 国家
        set:去重,无序。将contries列表中的国家去重,随机存放  -- 假设返回 - A 列表
        将A列表进行排序,从小到大,按首字母再其次俺第二个字母(可以根据ASCII码)-返回列表 -- country_list
        country_dict = 调用getCountryDict函数  将列表转换为字典
        country_num = 取出country_list的长度,返回国家有多少个
        """
        filename = 'names_train.csv.gz' if is_train_set else 'names_test.csv.gz'
        with gzip.open(filename, 'rt') as f:
            reader = csv.reader(f)
            rows = list(reader)
        self.names = [row[0] for row in rows]
        self.len = len(self.names)
        self.countries = [row[1] for row in rows]
        self.country_list = list(sorted(set(self.countries)))
        self.country_dict = self.getCountryDict()
        self.country_num = len(self.country_list)

    def __getitem__(self, index):
        """
        :param index:
        :return: 返回名字的索引,国家从小到大的索引位置,对应字典中的位置
        """

        return self.names[index], self.country_dict[self.countries[index]]

    def __len__(self):
        """
        :return: 求长度
        """

        return self.len

    def getCountryDict(self):
        """
        创建一个空字典 -- country_dict
        for循环,取出当前循环次数,和当前循环的名字
        存放字典,对应索引,
        :return:将列表转换为字典。(键,键值)
        """
        country_dict = dict()
        for idx, country_name in enumerate(self.country_list, 0):
            country_dict[country_name] = idx

        return country_dict

    def idx2country(self, index):
        """
        返回country_list的值
        """

        return self.country_list[index]

    def getCountriesNum(self):
        """
        :return: 国家的数量
        """

        return self.country_num


"""
实例化NameDataset类 -- trainset
利用DataLoader函数对数据进行处理,batch_size个数据为一组,shuffle打乱数据 -- trainloader
实例化NameDataset类 -- testset
利用DataLoader函数对数据进行处理,batch_size个数据为一组,shuffle不打乱数据 -- testloader

返回国家的数量(调用NameDataset类)
"""
trainset = NameDataset(is_train_set=True)
trainloader = DataLoader(trainset, batch_size=BATCH_SIZE, shuffle=True)
testset = NameDataset(is_train_set=False)
testloader = DataLoader(testset, batch_size=BATCH_SIZE, shuffle=False)
N_COUNTRY = trainset.getCountriesNum()

"""
^^^^^数据的处理阶段^^^^^
"""

def create_tensor(tensor):
    """
    传入张量
    判断USE_GPU:
    将数据传到cuda上
    """
    if USE_GPU:
        device = torch.device("cuda:0")
        tensor = tensor.to(device)

    return tensor


class RNNClassifier(torch.nn.Module):
    """
    RNNClassifier继承Module类
    重写__init__,_init_hidden,forward,方法。
    """
    def __init__(self, input_size, hidden_size, output_size, n_layers=1, bidirectional=True):
        """
        super超类
        :param input_size:输入数据维度
        :param hidden_size:记忆体维度
        :param output_size:输出数据维度
        :param n_layers:层数
        :param bidirectional:判断是双向还是单向传播
        Embedding:嵌入层,先对输入数据做一个预处理,从input_size维度到hidden维度
        GRU模型,hidden_size:,hidden_size:,n_layers:,
        fc:Linear:线性模型:hidden_size * n_directions(输入模型维度),输出模型维度
        """
        super(RNNClassifier, self).__init__()
        self.hidden_size = hidden_size
        self.n_layers = n_layers
        self.n_directions = 2 if bidirectional else 1
        self.embedding = torch.nn.Embedding(input_size, hidden_size)
        self.gru = torch.nn.GRU(hidden_size, hidden_size, n_layers,
                                bidirectional=bidirectional)
        self.fc = torch.nn.Linear(hidden_size * self.n_directions, output_size)

    def _init_hidden(self, batch_size):
        """
        搭建记忆体的维度(self.n_layers * self.n_directions,batch_size,hidden_size)
        返回:记忆体传到模型GPU上
        """
        hidden = torch.zeros(self.n_layers * self.n_directions,
                             batch_size, self.hidden_size)

        return create_tensor(hidden)

    def forward(self, input, seq_lengths):
        """
        数据流程
        batch_size = 输入数据的宽度,
        hidden的维度调用_init_hidden方法
        将数据进行embedding层;
        使用pack_padded_sequence函数得到 - gru_input
        将处理好的数据传入gru模型函数中返回 -- output,hidden
        判断是单向还是双向传播
        最后将记忆层进行星星层变换得到输出的结果,并返回
        forward:输入数据,时间长度
        :param input:输入数据
        :param seq_lengths:时间序列
        :return:对记忆体的参数进行fc全连接变换,输出,即out
        """
        #input shape: B x S --> S x B  转置
        input = input.t()
        batch_size = input.size(1)

        hidden = self._init_hidden(batch_size)
        embedding = self.embedding(input)

        #pack them up
        gru_input = pack_padded_sequence(embedding, seq_lengths)

        output, hidden = self.gru(gru_input, hidden)
        if self.n_directions == 2:
            hidden_cat = torch.cat([hidden[-1], hidden[-2]], dim=1)
        else:
            hidden_cat = hidden[-1]
        fc_output = self.fc(hidden_cat)

        return fc_output


def name2list(name):
    """
    :param name: 名字
    :return: 名字,长度
    """
    arr = [ord(c) for c in name]

    return arr, len(arr)


def make_tensors(names, countries):
    """
    for循环,调用name2list函数,传参数给--sequences_and_lengths
    取出名字
    取出长度,变成张量

    创建全是0.的维度为(len(name_sequences),seq_lengths.max()),并变为长整型 -- 行:名字数,列:最长的ascii名字
    遍历,并返回,最后构建seq_tensor[idx,:seq_len]的矩阵,  --- zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。

    排序,依据序列长度降序
    """
    sequences_and_lengths = [name2list(name) for name in names]
    name_sequences = [s1[0] for s1 in sequences_and_lengths]
    seq_lengths = torch.LongTensor([s1[1] for s1 in sequences_and_lengths])

    #make rensor of name, BatchSize x SeqLen
    seq_tensor = torch.zeros(len(name_sequences), seq_lengths.max()).long()
    for idx, (seq, seq_len) in enumerate(zip(name_sequences, seq_lengths), 0):
        seq_tensor[idx, :seq_len] = torch.LongTensor(seq)

    #sort by length to use pack_padded_sequence
    seq_lengths, perm_idx = seq_lengths.sort(dim=0, descending=True)
    seq_tensor = seq_tensor[perm_idx]
    countries = countries[perm_idx]

    return create_tensor(seq_tensor), \
        create_tensor(seq_lengths), \
        create_tensor(countries)


def time_since(since):
    """
    时间计时模块
    """
    s = time.time() - since
    m = math.floor(s / 60)
    s -= m * 60

    return '%dm %ds' % (m, s)


def trainModel():
    """
    loss初始为0在循环之外;
    将训练集传入,取出数据,生成输入数据,长度,标签
    放入classifier模型训练
    利用criterion函数计算损失值
    梯度归零
    反向传播
    优化器迭代,更新参数(权重,偏置)
    损失值累加
    输出
    :return:所有数据一次的损失
    """
    total_loss = 0
    for i, (names, countries) in enumerate(trainloader, 1):
        inputs, seq_lengths, target = make_tensors(names, countries)
        output = classifier(inputs, seq_lengths)
        loss = criterion(output, target)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        total_loss += loss.item()
        if i % 10 == 0:
            print(f'[{time_since(start)}] Epoch {epoch}', end='')
            print(f'[{i * len(inputs)} / {len(trainset)}]', end='')
            print(f'loss = {total_loss / (i * len(inputs))}')

    return total_loss


def testModel():
    """
    测试集
    不用计算梯度
    取出数据
    将特征放入,计算预测值
    求预测数据中的最大值,dim=1--每一行
    损失累加
    输出
    :return:错误率
    """
    correct = 0
    total = len(testset)
    print("evaluating trained model ...")
    with torch.no_grad():
        for i, (names, countries) in enumerate(testloader, 1):
            inputs, seq_lengths, target = make_tensors(names, countries)
            output = classifier(inputs, seq_lengths)
            pred = output.max(dim=1, keepdim=True)[1]
            correct += pred.eq(target.view_as(pred)).sum().item()

        percent = '%.2f' % (100 * correct / total)
        print(f'Test set: Accuracy {correct} / {total} {percent} %')

    return correct / total


if __name__ == '__main__':
    """
    模型RNNClassifier
    GPU运行
    损失函数criterion
    优化器Adam:初始化模型参数
    记录时间
    输出:一共输出多少次
    创建一个列表
        for循环对N_EPOCHS(1 - n_epochs+1)
        跑训练模型
        跑测试模型 -- acc
        将返回值依次存放在acc_list[]列表中
    画图部分
    x轴为acc_list的长度,间距为1
    y轴为acc_list的数值
    """
    classifier = RNNClassifier(N_CHARS, HIDDEN_SIZE, N_COUNTRY, N_LAYER)
    if USE_GPU:
        device = torch.device("cuda:0")
        classifier.to(device)

    criterion = torch.nn.CrossEntropyLoss()
    optimizer = torch.optim.Adam(classifier.parameters(), lr=0.001)

    start = time.time()
    print("Traning for %d epochs..." % N_EPOCHS)
    acc_list = []
    for epoch in range(1, N_EPOCHS + 1):
        #Train cycle
        trainModel()
        acc = testModel()
        acc_list.append(acc)

epoch = np.arange(1, len(acc_list) + 1, 1)
acc_list = np.array(acc_list)
plt.plot(epoch, acc_list)
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.grid()
plt.show()

你可能感兴趣的:(RNN,CNN,PyTorch,python,深度学习,机器学习,pytorch)