watch: PyTorch - 刘二 12 | RNN Basics

Table of contents

RNN Cell

  • 一个线性单元
  • 把输入x的维度(inputSize)变换到 hiddenSize
  • 处理带有时间序列的数据
  • x2 与 h1 共同决定 h2

t时刻的输入 $x_t \in \mathbb R^3$ 经过 RNN cell 转换,变成了一个隐状态变量 $h_t \in \mathbb R^5$, 因此RNN cell是一个线性层(矩阵运算)映射到另外一个维度空间,不过这个线性层是共享的。

$h_t$ 会参与下次 RNN cell 计算 $h_{t+1}$,把之前的信息合并。 在计算 $h_1$ 时,需要输入先验 $h_0$,如果没有先验,就输入与 $h_1, h_2...$ 同维度的零向量。

遍历数据集 $x_t \in \mathbb R^{\rm input\_size}$,做线性变换

$$ W^{\rm hidden\ size \times input\ size}_{hi} xₜ + b\_{hi} $$

变换到一个 hidden_size×1 的向量;

上一层的隐变量 $h_{t-1}$ 也进行线性变换 $W_{hh} h_{t-1} + b_{hh}$ 得到一个 hidden_size×1的向量, 它与 $x_t$ 的线性变换输出相加,得到的向量仍为 hidden_size × 1, 再做激活 tanh,算出隐向量 $h_t \in \mathbb R^{\rm hidden\_size}$

两个线性运算可以合一起:

$$ \begin{aligned} & W_{hh} h_{t-1} + W_{hi} x_{t} \\\ & = [W_{hh} \ \ W_{hi}]^{\rm h\ size \times (h\ size + i\ size)} \begin{bmatrix} h_{t-1} \\\ x_t \end{bmatrix}^{\rm (h\ size+i\ size) \times 1} \\\ & = h_t^{\rm h\ size \times 1} \end{aligned} $$

$h_t = \rm tanh(W_{hi} x_t + b_{hi} + W_{hh}h_{t-1}+b_{hh})$

在Pytorch中,可以自己构造 RNN cell,并处理序列的循环;也可以直接使用RNN。

自己创建RNN Cell: cell = torch.nn.RNNCell (input_size=i_size, hidden_size = h_size)

  • 用 cell 计算下一时刻的隐变量:h_1 = cell (x_1, h_0)

  • 这两个输入的 shape:x(batch_size, input_size),h(batch_size, hidden_size), h_1的维度与h_0一样。batch是一批的样本条数。

  • 数据集可以表达成一个张量:dataset.shape = (seqLen, batch_size, input_size)

  • 使用RNNCell:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    
    import torch
    batch_size = 1
    seq_len = 3     #有3个样本:x1,x2,x3
    input_size = 4  #x都是4x1的向量
    hidden_size =2  #h都是2×1的向量
    
    cell = torch.nn.RNNCell(
              input_size=input_size, 
              hidden_size=hidden_size
              )
    
    dataset = torch.randn(seq_len, batch_size, input_size)
    #初始化h0,全零
    hidden = torch.zeros(batch_size, hidden_size) 
    
    for idx, input in enumerate(dataset):
        hidden = cell(input, hidden)
    

RNN class

实例化RNN: cell = torch.nn.RNN(input_size = input_size, hidden_size=hidden_size, num_layer=num_layers)

RNN的输出有两个张量,调用:out, hidden = cell(inputs, hidden)

inputs 是整个输入序列,输入的 hidden 是 $h_0$,out 是所有的隐层输出 $h_1 \cdots h_N$,输出的 hidden 是最后一个 cell 的输出$h_N$。

inputs 的形状是 (seqLen, batch, input_size),hidden 的形状是 (numLayers, batch, hidden_size),numLayers 是RNN的层数,每层最终都会输出一个隐变量。 output的形状为(seqLen, batch, hidden_size)。输出hidden与输入hidden的形状一样

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import torch

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

cell = torch.nn.RNN(input_size = input_size, hidden_size= hidden_size, num_layers = num_layers)

inputs = torch.randn(seq_len, batch_size, input_size)
hidden = torch.zeros(num_layers, batch_size, hidden_size)

out, hidden = cell(inputs, hidden)

Example: Seq ➔ Seq

例子: 序列 ➔ 序列,把“hello"转换到“ohlol”

把输入“hello”变成由数字构成的向量:

  • 字符级别,为出现过的字符构造一个词典;
  • 词级别,为出现过的单词构造词典。

这里为每个元素分配索引,用索引代替字母。再把每个索引变成一个向量(独热码),向量的长度与词典的条数一样

$$ \begin{aligned} \begin{bmatrix} h \\\ e \\\ l \\\ l \\\ o \end{bmatrix} \underset{\longrightarrow}{词典有4条索引} \quad \begin{bmatrix} 1 \\\ 0 \\\ 2 \\\ 2 \\\ 3 \end{bmatrix} \rightarrow \begin{matrix} [0 & 1 & 0 & 0] \\\ [1 & 0 & 0 & 0] \\\ [0 & 0 & 1 & 0] \\\ [0 & 0 & 1 & 0] \\\ [0 & 0 & 0 & 1] \end{matrix} \end{aligned} $$
  1. 依次把 5 个独热向量输入 RNN,向量长度(input_size) = 4, output 是 5 个 RNN Cell的输出,每个输出对应于 4 个字母(h, e, l, o)中的一个,因此是一个多分类问题。

  2. 所以设置每个 hidden 是一个长度为 4 的向量,这 4 个线性输出分别对应(h,e,l,o)。 把这个向量传入 softmax就变成了一个概率分布,表示 4 个字母分别可能的概率。

  3. 再与真实标签的独热向量计算损失,即可用反向传播+梯度下降优化网络参数。

自己设计RNN Cell

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import torch

## Step-1 准备数据
input_size = 4  # 每个样本的独热向量的长度为4
hidden_size = 4 # 隐变量的长度为4,对应4个输出类别
batch_size = 1  # number of tokens

idx2char = ['e', 'h', 'l', 'o'] # 方便打印结果
x_data = [1, 0, 2, 2, 3]    # 样本 "hello"(索引)
y_data = [3, 1, 2, 3, 2]    # 输出 "ohlol" 的标签(真实类别), o是第4类,h是第2类

one_hot_lookup =[[1,0,0,0],
                 [0,1,0,0],
                 [0,0,1,0],
                 [0,0,0,1]]
# 把样本索引变成独热向量,其形状为 (seqSize, input_size) = (5, 4)
x_one_hot = torch.Tensor([one_hot_lookup[x] for x in x_data])

# 全部样本分成几个 batch,-1表示 batch 的个数 num_batch 自动计算
inputs = x_one_hot.view(-1, batch_size, input_size) # (5,1,4)

# label vector (seqSize, 1)。因为 batch_size 是 1,所以第 1 维度是 1
labels = torch.LongTensor(y_data).view(-1,1)   # (5,1)

## Step-2 设计模型
class Model(torch.nn.Module):   #继承自Module
    def __init__(self, input_size, hidden_size, batch_size):
        super(Model, self).__init__()
        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
            )   # 实例化 RNN Cell

    def forward(self, input, hidden):   # Module 里面的 __call__函数调用了forward方法
        # 用 input 和 hidden state 计算下一个 hidden state
        hidden = self.rnncell(input, hidden) # input: (batchSize, inputSize)
        return hidden   # (batchSize, hiddenSize)

    def init_hidden(self):  #生成默认的h0,全零矩阵
        return torch.zeros(self.batch_size, self.hidden_size)

# 实例化模型对象,batch_size 只有在构造默认 h0 时被用到
net = Model(input_size, hidden_size, batch_size)

## Step-3 损失和优化器
criterion = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(net.parameters(), lr=0.1)  #基于SGD的改进优化器

## Step-4 训练循环
n_iters = 15
for epoch in range(n_iters):
    loss = 0
    optimizer.zero_grad()       #梯度归零
    hidden = net.init_hidden()  #生成 h0
    print('Predicted string: ', end='')

    # 遍历每个 batch,每个 batch 里有 batch_size 个 token。
    # inputs:(num_batch, batchSize, inputSize)
    for input, label in zip(inputs, labels):   # input: (batchSize, inputSize), label: (batchSize,)
        # zip 是沿着矩阵的第 0 维度拼接,也就是沿着 num_batch 方向拼接,所以一个矩阵对应一个label。

        # 计算下一时刻的 hidden,维度为 (batchSize, hiddenSize)
        hidden = net(input, hidden) 

        # 累加各 batch 的损失(需要构造计算图,不可用item())
        loss += criterion(hidden, label)    

        # 按维度 1 找 hidden 里的最大值的下标,就属于那类
        _, idx = hidden.max(dim=1)  

        # 看一下输出了什么字符,虽然字符对了,但它的概率不是1,所以还有损失。
        print(idx2char[idx.item()], end='')

    loss.backward()     # 计算梯度
    optimizer.step()    # 更新一步
    print(f', Epoch [{epoch+1}/{n_iters}], loss ={loss.item():.4f}') #打印损失

调用pytorch的RNN类

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import torch

## 准备数据
input_size = 4  #共有helo 4种字符,需要用4元素的独热向量来表示每种字符
hidden_size = 4 #输出分别属于4类的概率
num_layers = 1
batch_size = 1  #每个batch是1个字符
seq_len = 5     #全部样本分成5个seq/batch:"h";"e";"l";"l";"o"

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] #把样本变成独热向量,其形状为seq×input_size

inputs = torch.Tensor(x_one_hot).view(seq_len, batch_size, input_size)

labels = torch.LongTensor(y_data)    #维度(seqSize×batchSize,1):torch.Size([5]),所有样本的标签(类别)

## 设计模型
class Model(torch.nn.Module):
    def __init__(self, input_size, hidden_size, batch_size, num_layers=1):
        super(Model, self).__init__()
        self.num_layers = num_layers
        self.batch_size = batch_size    #用于创建默认h0
        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):   #Module调用此方法,自动迭代数据集,给出最终输出
        hidden = torch.zeros(self.num_layers, self.batch_size, self.hidden_size) #如果在外面定义,这就不用写
        out, _ = self.rnn(input, hidden)
        return out.view(-1, self.hidden_size) #输出变成两维的(seqLen×batchSize, hiddenSize),交叉熵损失只能接受二维的Tensor和一维的labels:一条样本的向量对应一个label

net = Model(input_size, hidden_size, batch_size, num_layers)

## 损失和优化器
criterion = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(net.parameters(), lr=0.05) #lr 0.1比较好

## 训练循环
for epoch in range(15):
    optimizer.zero_grad()
    outputs = net(inputs)   #inputs的维度:SeqLen*BatchSize*InputSize,outputs的维度:SeqLen*BatchSize*HiddenSize
    loss = criterion(outputs, labels)   #labels维度是SeqLen×BatchSize×1,也就是(5,1)
    loss.backward()
    optimizer.step()

    _, idx = outputs.max(dim=1)
    idx = idx.data.numpy()
    print('Predicted:', ''.join([idx2char[x] for x in idx]), end='') #把4个字符拼成一个单词
    print(',Epoch [%d/15] loss =%.3f' % (epoch+1, loss.item())) #打印损失

独热向量在编码词/字符时:

  1. 独热向量维度太高,字符级别需128维,单词级别维度太高
  2. 向量太稀疏
  3. 是硬编码的

希望吧 单词/字符 联系到一个低维、稠密、从数据中学习到的向量,流行又强大的方法是嵌入层Embedding。把高维稀疏样本映射到低维稠密的空间(数据降维)。

独热向量$x_n$通过嵌入层 Embed 变成稠密的表示,经过RNN线性变换后,再用一个线性层,让最后的隐变量输出与分类的数量一致

4维转5维,构建一个查找表:

查找表做转置,再乘以输入的独热向量,就可取出“对应行”

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
num_class = 4       #类别
input_size = 4      #输入样本是4维的
hidden_size = 8     #隐变量输出是8维
embedding_size = 10 #把输入从4维嵌入到10维空间
num_layers = 2      #2层RNN
batch_size = 1
seq_len = 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):
        super(Model, self).__init__()
        self.emb = torch.nn.Embedding(input_size, embedding_size) #嵌入层查找表的大小:inputSize×embeddingSize,对输入数据做维度转换
        self.rnn = torch.nn.RNN(input_size=embedding_size,
                                hidden_size=hidden_size,
                                num_layers=num_layers,
                                batch_first=True)   #RNN输入:(batchSize, seqLen, embeddingSize),RNN输出:(batchSize, seqLen, hiddenSize)
        self.fc = torch.nn.Linear(hidden_size, num_class) #维度变换: 从hidden_size到类别数量

    def forward(self, x):
        hidden = torch.zeros(num_layers, x.size(0), hidden_size)
        x = self.emb(x) #(batch,seqLen, embeddingSize) 把长整形的张量转变成嵌入层稠密的向量
        x, _ = self.rnn(x, hidden)
        x = self.fc(x)
        return x.view(-1,num_class) #维度等于类别数

net = Model()

#后面都一样
criterion = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(net.parameters(), lr=0.05)

for epoch in range(15):
    optimizer.zero_grad()
    outputs = net(inputs)   #inputs的维度:SeqLen*BatchSize*InputSize,outputs的维度:SeqLen*BatchSize*HiddenSize
    loss = criterion(outputs, labels)   #labels维度是SeqLen×BatchSize×1,也就是(5,1)
    loss.backward()
    optimizer.step()

    _, idx = outputs.max(dim=1) #取出值最大的维度的索引,也就是所属的第几类。
    idx = idx.data.numpy()  #索引从0开始
    print('Predicted:', ''.join([idx2char[x] for x in idx]), end='') #把4个字符拼成一个单词
    print(',Epoch [%d/15] loss =%.3f' % (epoch+1, loss.item())) #打印损失

用RNN对MNIST图片分类

感觉里面的流程挺规范的。

  • 初始化h0 为一个对角矩阵;
  • 用了3层RNN,只用10个epoch就达到96%的accuracy了。

大概原理

把MNIST中每张图片看成一个序列,这个序列含有28个$x$(对应每一行像素),x的维度是28。每行像素都变换到一个h,这个h会参与计算下一行的h,最终得到第28行的h,将此h输入线性全连接层,变换到10维,每一维对应着0-9的每一类。然后这个10维的向量通过softmax,就是属于每类的概率了。

代码

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
import torch
import torch.nn as nn
import torch.nn.functionall as F
import torch.optim as optim
import torchvision
import torchvision.transforms as transforms

import numpy as np
import matplotlib.pyplot as plt

# 1. 加载数据集 MNIST
batch_size = 128
train_dataset = torchvision.datasets.MNIST(root='./',
                                           train=True,
                                           transform=transforms.ToTensor(),
                                           download=True) #加载训练集
test_dataset = torchvision.datasets.MNIST(root='./',
                                          train=False,
                                          transform=transforms.ToTensor())  #加载测试集

train_loader = torch.utils.data.DataLoader(dataset=train_dataset,
                                           batch_size=batch_size,
                                           shuffle=True) #构造数据加载器,每次迭代从数据集中取出batchSize个样本,每个epoch都不同
test_loader = torch.utils.data.DataLoader(dataset=test_dataset,
                                          batch_size=batch_size,
                                          shuffle=False)

# 查看一下数据
def imshow(img):
    npimg = img.numpy()
    plt.imshow(np.transpose(npimg,(1,2,0)))

dataiter = iter(train_loader)   #取出一份128张图片
images, labels = dataiter.next()

imshow(torchvision.utils.make_grid(images,nrow=15)) #一排15张图

# 2. 定义模型
N_STEPS = 28    # 1张图片是1个序列,所以1个序列包含28个样本
N_INPUTS = 28   # 输入数据的维度(1行有28个像素)
N_NEURONS = 150 # RNN中间的特征的大小(hiddenSize)
N_OUTPUT = 10   # 输出数据的维度(分类的个数)
N_EPHOCS = 10   # epoch的大小(训练10轮)
N_LAYERS = 3    # 3层RNN

class ImageRNN(nn.Module):  #继承自nn.Module
    def __init__(self, batch_size, n_inputs, n_neurons, n_outputs, n_layers):
        super(ImageRNN, self).__init__()
        self.batch_size = batch_size    #每次输入batchSize张图片
        self.n_inputs = n_inputs    # 输入的维度
        self.n_outputs = n_outputs  # 分类的大小
        self.n_neurons = n_neurons  # RNN中输出的维度
        self.n_layers = n_layers    # RNN中的层数
        self.basic_rnn = nn.RNN(self.n_inputs, self.n_neurons, num_layers=self.n_layers)    #实例化RNN对象,inputSize,hiddenSize
        self.FC = nn.Linear(self.n_neurons, self.n_outputs)

    def init_hidden(self):  #生成h0是一个对角矩阵
        # (num_layers, batch_size, n_neurons)
        # initialize hidden weights with zero values
        # 这个是net的memory, 初始化memory为0
        return (torch.zeros(self.n_layers, self.batch_size, self.n_neurons).to(device))

    def forward(self,x):    #计算RNN Cell的输出
        # transforms x to dimensions : n_step × batch_size × n_inputs
        x = x.permute(1,0,2) # 需要把n_step放在第一个维度
        self.batch_size = x.size(1) # 每次需要重新计算batch_size, 因为可能会出现不够一个batch的情况
        self.hidden = self.init_hidden() # 初始化hidden state
        rnn_out, self.hidden = self.basic_rnn(x,self.hidden) # 前向传播
        out = self.FC(rnn_out[-1]) # 求出每一类的概率
        return out.view(-1,self.n_outputs) # 最终输出大小 : batch_size × n_output(10)。然后接softmax找出所属类别,计算损失。

# 测试一下
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')   #方便之后使用gpu运算

model = ImageRNN(batch_size, N_INPUTS, N_NEURONS, N_OUTPUT, N_LAYERS).to(device)    #构造RNN模型

model.basic_rnn.weight_hh_l0.data = torch.eye(n=N_NEURONS, m=N_NEURONS, out=None).to(device)    # 初始化模型的weight为对角矩阵
model.basic_rnn.weight_hh_l1.data = torch.eye(n=N_NEURONS, m=N_NEURONS, out=None).to(device)
model.basic_rnn.weight_hh_l2.data = torch.eye(n=N_NEURONS, m=N_NEURONS, out=None).to(device)

dataiter = iter(train_loader)   # 取1份数据
images, labels = dataiter.next()
model.hidden = model.init_hidden()  #初始化h0
logits = model(images.view(-1,28,28).to(device)) #输入模型
print(logits[0:2])  #打印前2张图的hidden输出:10维向量

# 3. 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(),lr=0.001)

def get_accuracy(logit, target, batch_size): #用来最后计算模型的准确率
    corrects = (torch.max(logit, 1)[1].view(target.size()).data == target.data).sum()
    accuracy = 100.0 * corrects/batch_size
    return accuracy.item()

# 4. 训练
for epoch in range(N_EPHOCS):
    train_running_loss = 0.0
    train_acc = 0.0
    model.train()

    # trainging round
    for i, data in enumerate(train_loader): #每次取出一个batch
        optimizer.zero_grad()   #梯度清零

        # reset hidden states
        model.hidden = model.init_hidden()  #初始化h0

        # get inputs
        inputs, labels = data   #输入一个batch的样本和标签
        inputs = inputs.view(-1,28,28).to(device)
        labels = labels.to(device)

        # forward+backward+optimize
        outputs = model(inputs)

        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()

        train_running_loss = train_running_loss + loss.detach().item()
        train_acc = train_acc + get_accuracy(outputs, labels, batch_size)
    model.eval()
    print('Epoch : {:0>2d} | Loss : {:<6.4f} | Train Accuracy : {:<6.2f}%'.format(epoch, train_running_loss/i, train_acc/i))

# 5. 评价模型:计算测试集准确率
est_acc = 0.0
for i,data in enumerate(test_loader,0):
    inputs, labels = data
    labels = labels.to(device)
    inputs = inputs.view(-1,28,28).to(device)

    outputs = model(inputs)

    thisBatchAcc = get_accuracy(outputs, labels, batch_size)
    print("Batch:{:0>2d}, Accuracy : {:<6.4f}%".format(i,thisBatchAcc))
    test_acc = test_acc + thisBatchAcc

print('============平均准确率===========')
print('Test Accuracy : {:<6.4f}%'.format(test_acc/i))   #96%

# 6. 定义hook, 查看模型中间过程

k折交叉验证

《动手学深度学习》的pytorch版

返回第i折训练和验证数据

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
def get_k_fold_data(k,i,X,y): #我不想把标签分出来,Dataset对象可以分
    assert k>1
    fold_size = X.shape[0] // k     #先做除法,再向下取整(不大于)
    X_train, y_train = None, None

    for j in range(k):
        idx = slice(j*fold_size, (j+1)*fold_size) #切片函数slice(start, end, step)
        X_part, y_part = X[idx,:], y[idx]

        if j == i:
            X_valid, y_valid = X_part, y_part
        elif X_train is None:
            X_train, y_train = X_part, y_part
        else:
            X_train = torch.cat((X_train, X_part), dim=0) #增加行数
            y_train = torch.cat((y_train, y_part), dim=0)
    return X_train, y_train, X_valid, y_valid

训练k次

1
2
3
4
5
def k_fold(k, X_train, num_epochs, learning_rate, weight_decay, batch_size):
    train_ls_sum, valid_ls_sum = 0, 0
    for i in range(k):
        data = get_k_fold_data(k, i, X_train)
        ....
Built with Hugo
Theme Stack designed by Jimmy