7.md 73.1 KB
Newer Older
W
wizardforcel 已提交
1 2 3 4 5 6 7 8
# 附录

# 1.深度学习和 PyTorch 简介

## 活动 1.01:创建单层神经网络

### 解决方案

W
wizardforcel 已提交
9
1.  导入所需的库,包括pandas,用于导入CSV文件。
W
wizardforcel 已提交
10

W
wizardforcel 已提交
11 12 13 14 15 16
    ```py
    import pandas as pd
    import torch
    import torch.nn as nn
    import matplotlib.pyplot as plt
    ```
W
wizardforcel 已提交
17

W
wizardforcel 已提交
18
2.  读取包含数据集的CSV文件。
W
wizardforcel 已提交
19

W
wizardforcel 已提交
20 21 22
    ```py
    data = pd.read_csv("SomervilleHappinessSurvey2015.csv")
    ```
W
wizardforcel 已提交
23

W
wizardforcel 已提交
24
3.  将输入特征与目标分开。注意,目标位于CSV文件的第一列。将值转换为张量,确保值转换为浮点数。
W
wizardforcel 已提交
25

W
wizardforcel 已提交
26 27 28 29
    ```py
    x = torch.tensor(data.iloc[:,1:].values).float()
    y = torch.tensor(data.iloc[:,:1].values).float()
    ```
W
wizardforcel 已提交
30

W
wizardforcel 已提交
31
4.  定义模型的架构,并将其存储在一个名为`model`的变量中。记住要创建一个单层模型。
W
wizardforcel 已提交
32

W
wizardforcel 已提交
33 34 35 36
    ```py
    model = nn.Sequential(nn.Linear(6, 1),
                          nn.Sigmoid())
    ```
W
wizardforcel 已提交
37

W
wizardforcel 已提交
38
5.  定义要使用的损失函数。使用MSE损失函数。
W
wizardforcel 已提交
39

W
wizardforcel 已提交
40 41 42
    ```py
    loss_function = torch.nn.MSELoss()
    ```
W
wizardforcel 已提交
43

W
wizardforcel 已提交
44
6.  定义你模型的优化器。使用亚当优化器和学习率`0.01`
W
wizardforcel 已提交
45

W
wizardforcel 已提交
46 47 48
    ```py
    optimizer = torch.optim.Adam(model.parameters(), lr=0.01)
    ```
W
wizardforcel 已提交
49

W
wizardforcel 已提交
50
7.  运行优化100次迭代。每迭代10次,打印并保存损失值。
W
wizardforcel 已提交
51

W
wizardforcel 已提交
52 53 54 55 56 57 58 59 60 61 62 63
    ```py
    losses = []
    for i in range(100):
        y_pred = model(x)
        loss = loss_function(y_pred, y)
        losses.append(loss.item())
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        if i%10 == 0:
            print(loss.item())
    ```
W
wizardforcel 已提交
64

W
wizardforcel 已提交
65
    最终损失应约为`0.24`。
W
wizardforcel 已提交
66

W
wizardforcel 已提交
67
8.  做一个线图来显示每个迭代步骤的损失值。
W
wizardforcel 已提交
68

W
wizardforcel 已提交
69 70
    ```py
    plt.plot(range(0,100), losses)
W
wizardforcel 已提交
71
    plt.show()
W
wizardforcel 已提交
72
    ```
W
wizardforcel 已提交
73 74 75 76 77

    结果图应如下所示:

![Figure 1.4: Loss function throughout the training process ](img/B15778_01_04.jpg)

W
wizardforcel 已提交
78
图 1.4:整个训练过程中的损失功能
W
wizardforcel 已提交
79

W
wizardforcel 已提交
80
这意味着训练过程能够使损失函数最小化,这意味着结果模型将可能能够绘制出市民对城市服务的满意度与他们对行政管理是否满意之间的关系。
W
wizardforcel 已提交
81 82 83

注意

W
wizardforcel 已提交
84
要访问此特定部分的源代码,请参考[这里](https://packt.live/2ZufWiI)
W
wizardforcel 已提交
85

W
wizardforcel 已提交
86
您也可以通过[这里](https://packt.live/2BZhyZF)在线运行此示例。 您必须执行整个笔记本才能获得所需的结果。
W
wizardforcel 已提交
87 88 89 90 91 92 93

# 2.神经网络的构建基块

## 活动 2.01:执行数据准备

### 解决方案

W
wizardforcel 已提交
94
1.  导入所需的库。
W
wizardforcel 已提交
95

W
wizardforcel 已提交
96 97 98
    ```py
    import pandas as pd
    ```
W
wizardforcel 已提交
99

W
wizardforcel 已提交
100
2.  使用pandas,加载`.csv`文件。
W
wizardforcel 已提交
101

W
wizardforcel 已提交
102 103 104 105
    ```py
    data = pd.read_csv("YearPredictionMSD.csv", nrows=50000)
    data.head()
    ```
W
wizardforcel 已提交
106 107 108

    注意

W
wizardforcel 已提交
109
    为避免内存限制,在读取文本文件时,请使用`nrows`自变量,以读取整个数据集的较小部分。 在前面的示例中,我们正在读取前 50,000 行。
W
wizardforcel 已提交
110 111 112 113 114 115 116

    输出如下:

    ![Figure 2.33: YearPredictionMSD.csv ](img/B15778_02_33.jpg)

    图 2.33:YearPredictionMSD.csv

W
wizardforcel 已提交
117
3.  核实数据集中是否存在任何定性数据。
W
wizardforcel 已提交
118

W
wizardforcel 已提交
119
    ```py
W
wizardforcel 已提交
120
    cols = data.columns
W
wizardforcel 已提交
121 122 123
    num_cols = data._get_numeric_data().columns
    list(set(cols) - set(num_cols))
    ```
W
wizardforcel 已提交
124 125 126

    输出应为空列表,这意味着没有定性特征。

W
wizardforcel 已提交
127
4.  检查是否有缺失值。
W
wizardforcel 已提交
128

W
wizardforcel 已提交
129
    如果在先前用于此目的的代码行中添加一个附加的`sum()`函数,则将获得整个数据集中的缺失值之和,而无需按列进行区分:
W
wizardforcel 已提交
130

W
wizardforcel 已提交
131 132 133
    ```py
    data.isnull().sum().sum()
    ```
W
wizardforcel 已提交
134

W
wizardforcel 已提交
135
    输出应为`0`,这意味着所有要素均不包含缺失值。
W
wizardforcel 已提交
136

W
wizardforcel 已提交
137
5.  检查是否有异常值。
W
wizardforcel 已提交
138

W
wizardforcel 已提交
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
    ```py
    outliers = {}
    for i in range(data.shape[1]):
        min_t = data[data.columns[i]].mean() \
                - (3 * data[data.columns[i]].std())
        max_t = data[data.columns[i]].mean() \
                + (3 * data[data.columns[i]].std())
        count = 0
        for j in data[data.columns[i]]:
            if j < min_t or j > max_t:
                count += 1
        percentage = count/data.shape[0]
        outliers[data.columns[i]] = "%.3f" % percentage
    print(outliers)
    ```
W
wizardforcel 已提交
154

W
wizardforcel 已提交
155
    输出字典应显示所有要素均不包含代表超过 5% 数据的离群值。
W
wizardforcel 已提交
156

W
wizardforcel 已提交
157
6.  将特征从目标数据中分离出来。
W
wizardforcel 已提交
158

W
wizardforcel 已提交
159 160 161 162
    ```py
    X = data.iloc[:, 1:]
    Y = data.iloc[:, 0]
    ```
W
wizardforcel 已提交
163

W
wizardforcel 已提交
164
7.  使用标准化方法对特征数据进行重新标定。
W
wizardforcel 已提交
165

W
wizardforcel 已提交
166 167 168 169
    ```py
    X = (X - X.mean())/X.std()
    X.head()
    ```
W
wizardforcel 已提交
170 171 172 173 174 175 176

    输出如下:

    ![Figure 2.34: Rescaled features data ](img/B15778_02_34.jpg)

    图 2.34:重新缩放的要素数据

W
wizardforcel 已提交
177
8.  将数据分成三组:训练、验证和测试。使用你喜欢的方法。
W
wizardforcel 已提交
178

W
wizardforcel 已提交
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
    ```py
    from sklearn.model_selection import train_test_split
    X_shuffle = X.sample(frac=1, random_state=0)
    Y_shuffle = Y.sample(frac=1, random_state=0)
    x_new, x_test, \
    y_new, y_test = train_test_split(X_shuffle, \
                                     Y_shuffle, \
                                     test_size=0.2, \
                                     random_state=0)
    dev_per = x_test.shape[0]/x_new.shape[0]
    x_train, x_dev, \
    y_train, y_dev = train_test_split(x_new, \
                                      y_new, \
                                      test_size=dev_per, \
                                      random_state=0)
    ```
W
wizardforcel 已提交
195

W
wizardforcel 已提交
196
9.  打印所得形状如下。
W
wizardforcel 已提交
197

W
wizardforcel 已提交
198 199 200 201 202
    ```py
    print(x_train.shape, y_train.shape)
    print(x_dev.shape, y_dev.shape)
    print(x_test.shape, y_test.shape)
    ```
W
wizardforcel 已提交
203 204 205

    输出应如下所示:

W
wizardforcel 已提交
206
    ```py
W
wizardforcel 已提交
207 208 209
    (30000, 90) (30000, )
    (10000, 90) (10000, )
    (10000, 90) (10000, )
W
wizardforcel 已提交
210
    ```
W
wizardforcel 已提交
211 212 213

    注意

W
wizardforcel 已提交
214
    要访问此特定部分的源代码,请参考[这里](https://packt.live/31ukVTj)。
W
wizardforcel 已提交
215

W
wizardforcel 已提交
216
    您也可以通过[这里](https://packt.live/3dLWMdd)在线运行此示例。 您必须执行整个笔记本才能获得所需的结果。
W
wizardforcel 已提交
217 218 219 220 221

## 活动 2.02:为回归问题开发深度学习解决方案

### 解决方案

W
wizardforcel 已提交
222
1.  导入所需的库。
W
wizardforcel 已提交
223 224 225 226 227

    进口火炬

    将 torch.nn 导入为 nn

W
wizardforcel 已提交
228
2.  将我们在上一个活动中创建的所有三组数据的特征从目标中分割出来。将DataFrames转换为张量。
W
wizardforcel 已提交
229 230 231 232 233 234 235 236 237 238 239 240 241

    x_train = torch.tensor(x_train.values).float()

    y_train =火炬张量(y_train.values).float()

    x_dev = torch.tensor(x_dev.values).float()

    y_dev = torch.tensor(y_dev.values).float()

    x_test = torch.tensor(x_test.values).float()

    y_test = torch.tensor(y_test.values).float()

W
wizardforcel 已提交
242
3.  定义网络的架构。可以自由尝试不同的层数和每层单元数的组合。
W
wizardforcel 已提交
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257

    模型= nn.Sequential(nn.Linear(x_train.shape [1],10),\

    nn.ReLU(),\

    nn.Linear(10,7),\

    nn.ReLU(),\

    nn.Linear(7,5),\

    nn.ReLU(),\

    nn.Linear(5,1))

W
wizardforcel 已提交
258
4.  定义损失函数和优化器算法。
W
wizardforcel 已提交
259 260 261 262 263

    loss_function = torch.nn.MSELoss()

    优化程序= torch.optim.Adam(model.parameters(),lr = 0.01)

W
wizardforcel 已提交
264
5.  使用`for`循环来训练网络,迭代步数为3000步。
W
wizardforcel 已提交
265 266 267 268 269 270 271 272 273 274 275 276 277

    对于我的范围(3000):

    y_pred = model(x_train).squeeze()

    损失= loss_function(y_pred,y_train)

    Optimizer.zero_grad()

    loss.backward()

    Optimizer.step()

W
wizardforcel 已提交
278
    如果 i% 250 == 0:
W
wizardforcel 已提交
279 280 281

    打印(i,loss.item())

W
wizardforcel 已提交
282
6.  通过对测试集的第一个实例进行预测,并与地面真相进行比较来测试你的模型。
W
wizardforcel 已提交
283 284 285 286 287 288 289 290 291 292 293 294 295

    之前=模型(x_test [0])

    print(“地面真相:”,y_test [0] .item(),\

    “预测:”,pred.item())

    您的输出应类似于以下内容:

    基本事实:1995.0 预测:1998.0279541015625

    注意

W
wizardforcel 已提交
296
    要访问此特定部分的源代码,请参考[这里](https://packt.live/2CUDSnP)。
W
wizardforcel 已提交
297

W
wizardforcel 已提交
298
    您也可以通过[这里](https://packt.live/3eQ1yI2)在线运行此示例。 您必须执行整个笔记本才能获得所需的结果。
W
wizardforcel 已提交
299 300 301 302 303 304 305

# 3.使用 DNN 的分类问题

## 活动 3.01:构建人工神经网络

解:

W
wizardforcel 已提交
306
1.  导入以下库:
W
wizardforcel 已提交
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327

    将熊猫作为 pd 导入

    将 numpy 导入为 np

    从 sklearn.model_selection 导入 train_test_split

    从 sklearn.utils 导入 shuffle

    从 sklearn.metrics 导入 precision_score

    进口火炬

    从火炬进口 nn,乐观

    导入功能为 F 的 torch.nn。

    导入 matplotlib.pyplot 作为 plt

    torch.manual_seed(0)

W
wizardforcel 已提交
328
2.  读取之前准备好的数据集,该数据集应该命名为`dccc_prepared.csv`
W
wizardforcel 已提交
329 330 331 332 333 334 335 336 337 338 339

    数据= pd.read_csv(“ dccc_prepared.csv”)

    data.head()

    输出应如下所示:

    ![Figure 3.14: dccc_prepared.csv ](img/B15778_03_14.jpg)

    图 3.14:dccc_prepared.csv

W
wizardforcel 已提交
340
3.  将特征与目标分开。
W
wizardforcel 已提交
341 342 343 344 345

    X = data.loc [:,:-1]

    y =数据[“下个月的默认付款”]

W
wizardforcel 已提交
346
4.  使用scikit-learn的`train_test_split`函数,将数据集分割成训练集、验证集和测试集。使用60:20:20的分割比例。将`random_state`设置为0。
W
wizardforcel 已提交
347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379

    X_new,X_test,\

    y_new,y_test = train_test_split(X,y,test_size = 0.2,\

    random_state = 0)

    dev_per = X_test.shape [0] /X_new.shape [0]

    X_train,X_dev,\

    y_train,y_dev = train_test_split(X_new,y_new,\

    test_size = dev_per,\

    random_state = 0)

    您可以使用以下代码打印每个集合的最终形状:

    print(“训练集:”,X_train.shape,y_train.shape)

    print(“验证集:”,X_dev.shape,y_dev.shape)

    print(“测试集:”,X_test.shape,y_test.shape)

    每个集合的最终形状如下所示:

    训练集:(28036,22)(28036,)

    验证集:(9346,22)(9346,)

    测试集:(9346,22)(9346,)

W
wizardforcel 已提交
380
5.  将验证集和测试集转换为张量,记住特征矩阵应该是`float`类型,而目标矩阵不应该。训练集暂不转换,因为它们将进行进一步的转换。
W
wizardforcel 已提交
381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417

    X_dev_torch = torch.tensor(X_dev.values).float()

    y_dev_torch = torch.tensor(y_dev.values)

    X_test_torch = torch.tensor(X_test.values).float()

    y_test_torch =火炬张量(y_test.values)

6.  Build a custom module class for defining the layers of the network. Include a forward function that specifies the activation functions that will be applied to the output of each layer. Use **ReLU** for all the layers, except for the output, where you should use **log_softmax**:

    类 Classifier(nn.Module):

    def __init __(self,input_size):

    super().__ init __()

    self.hidden_​​1 = nn.Linear(input_size,10)

    self.hidden_​​2 = nn.Linear(10,10)

    self.hidden_​​3 = nn.Linear(10,10)

    self.output = nn.Linear(10,2)

    def forward(self,x):

    z = F.relu(self.hidden_​​1(x))

    z = F.relu(self.hidden_​​2(z))

    z = F.relu(self.hidden_​​3(z))

    out = F.log_softmax(self.output(z),dim = 1)

    返回

W
wizardforcel 已提交
418
7.  Instantiate the model and define all the variables required to train the model. Set the number of epochs to`50`and the batch size to`128`. Use a learning rate of`0.001`:
W
wizardforcel 已提交
419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499

    模型=分类器(X_train.shape [1])

    准则= nn.NLLLoss()

    优化程序= optim.Adam(model.parameters(),lr = 0.001)

    时代= 50

    batch_size = 128

8.  Train the network using the training sets' data. Use the validation sets to measure performance. To do this, save the loss and the accuracy for both the training and validation sets in each epoch:

    train_losses,dev_losses,

    train_acc,dev_acc = [],[],[],[]

    对于范围内的 e(历元):

    X_,y_ = shuffle(X_train,y_train)

    running_loss = 0

    running_acc = 0

    迭代次数= 0

    对于范围(0,len(X_),batch_size)中的 i:

    迭代次数== 1

    b =我+ batch_size

    X_batch = torch.tensor(X_.iloc [i:b,:]。values).float()

    y_batch = torch.tensor(y_.iloc [i:b] .values)

    pred =模型(X_batch)

    损失=标准(pred,y_batch)

    Optimizer.zero_grad()

    loss.backward()

    Optimizer.step()

    running_loss + = loss.item()

    ps = torch.exp(pred)

    top_p,top_class = ps.topk(1,暗= 1)

    running_acc + =精度得分(y_batch,top_class)

    dev_loss = 0

    acc = 0

    使用 torch.no_grad():

    pred_dev =模型(X_dev_torch)

    dev_loss =条件(pred_dev,y_dev_torch)

    ps_dev = torch.exp(pred_dev)

    top_p,top_class_dev = ps_dev.topk(1,暗= 1)

    acc = precision_score(y_dev_torch,top_class_dev)

    train_losses.append(running_loss / iterations)

    dev_losses.append(dev_loss)

    train_acc.append(running_acc / iterations)

    dev_acc.append(acc)

    print(“ Epoch:{} / {} ..” .format(e + 1,epochs),\

W
wizardforcel 已提交
500
    “训练损失:{:. 3f} ..” \
W
wizardforcel 已提交
501 502 503 504 505

    .format(running_loss / iterations),\

    “验证损失:{:. 3f} ..” .format(dev_loss),\

W
wizardforcel 已提交
506
    “训练准确率:{:. 3f} ..” \
W
wizardforcel 已提交
507 508 509

    .format(running_acc / iterations),\

W
wizardforcel 已提交
510
    “验证准确率:{:. 3f}”。format(acc))
W
wizardforcel 已提交
511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535

9.  Plot the loss of both sets:

    图 = plt.figure(figsize =(15,5))

    plt.plot(train_losses,label ='训练损失')

    plt.plot(dev_losses,label ='Validation loss')

    plt.legend(frameon = False,fontsize = 15)

    plt.show()

    考虑到改组训练数据可能会得出略有不同的结果,结果图应与此处显示的图相似,尽管有所不同。

    ![Figure 3.15: A plot displaying the training and validation losses ](img/B15778_03_15.jpg)

    图 3.15:显示训练和验证损失的图

10.  Plot the accuracy of both sets:

    无花果= plt.figure(figsize =(15,5))

    plt.plot(train_acc,label =“训练精度”)

W
wizardforcel 已提交
536
    plt.plot(dev_acc,label =“验证准确率”)
W
wizardforcel 已提交
537 538 539 540 541 542 543 544 545 546 547 548 549

    plt.legend(frameon = False,fontsize = 15)

    plt.show()

    这是从此代码段派生的图:

![Figure 3.16: A plot displaying the accuracy of the sets ](img/B15778_03_16.jpg)

图 3.16:显示集合精度的图

注意

W
wizardforcel 已提交
550
要访问此特定部分的源代码,请参考[这里](https://packt.live/2Vz6BoK)
W
wizardforcel 已提交
551

W
wizardforcel 已提交
552
您也可以通过[这里](https://packt.live/2NNBuRS)在线运行此示例。 您必须执行整个笔记本才能获得所需的结果。
W
wizardforcel 已提交
553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647

## 练习 3.02:提高模型的性能

解:

1.  Import the same libraries that you used in the previous activity:

    将熊猫作为 pd 导入

    将 numpy 导入为 np

    从 sklearn.model_selection 导入 train_test_split

    从 sklearn.utils 导入 shuffle

    从 sklearn.metrics 导入 precision_score

    进口火炬

    从火炬进口 nn,乐观

    导入功能为 F 的 torch.nn。

    导入 matplotlib.pyplot 作为 plt

    torch.manual_seed(0)

2.  Load the data and split the features from the target. Next, split the data into the three subsets (training, validation, and testing) using a 60:20:20 split ratio. Finally, convert the validation and testing sets into PyTorch tensors, just as you did in the previous activity:

    数据= pd.read_csv(“ dccc_prepared.csv”)

    X = data.loc [:,:-1]

    y =数据[“下个月的默认付款”]

    X_new,X_test,\

    y_new,y_test = train_test_split(X,y,test_size = 0.2,\

    random_state = 0)

    dev_per = X_test.shape [0] /X_new.shape [0]

    X_train,X_dev,\

    y_train,y_dev = train_test_split(X_new,y_new,\

    test_size = dev_per,\

    random_state = 0)

    X_dev_torch = torch.tensor(X_dev.values).float()

    y_dev_torch = torch.tensor(y_dev.values)

    X_test_torch = torch.tensor(X_test.values).float()

    y_test_torch =火炬张量(y_test.values)

3.  Considering that the model is suffering from high bias, the focus should be on increasing the number of epochs or increasing the size of the network by adding additional layers or units to each layer. The aim should be to approximate the accuracy over the validation set to 80%.

    之后,将显示性能最佳的模型,该模型是在几次微调尝试之后实现的。 首先,定义模型架构和正向传递,如以下代码片段所示:

    类 Classifier(nn.Module):

    def __init __(self,input_size):

    super().__ init __()

    self.hidden_​​1 = nn.Linear(input_size,100)

    self.hidden_​​2 = nn.Linear(100,100)

    self.hidden_​​3 = nn.Linear(100,50)

    self.hidden_​​4 = nn.Linear(50,50)

    self.output = nn.Linear(50,2)

    self.dropout = nn.Dropout(p = 0.1)

    def forward(self,x):

    z = self.dropout(F.relu(self.hidden_​​1(x)))

    z = self.dropout(F.relu(self.hidden_​​2(z)))

    z = self.dropout(F.relu(self.hidden_​​3(z)))

    z = self.dropout(F.relu(self.hidden_​​4(z)))

    out = F.log_softmax(self.output(z),dim = 1)

    返回

W
wizardforcel 已提交
648
    接下来,定义训练过程的不同参数。 这包括损失函数,优化算法,批量大小和时期数,如以下代码所示:
W
wizardforcel 已提交
649 650 651 652 653 654 655 656 657 658 659

    模型=分类器(X_train.shape [1])

    准则= nn.NLLLoss()

    优化程序= optim.Adam(model.parameters(),lr = 0.001)

    时代= 4000

    batch_size = 128

W
wizardforcel 已提交
660
    最后,按照以下代码片段处理训练过程:
W
wizardforcel 已提交
661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723

    train_losses,dev_losses,train_acc,dev_acc = [],[],[],[]

    x_axis = []

    对于范围(1,历元+1)中的 e:

    X_,y_ = shuffle(X_train,y_train)

    running_loss = 0

    running_acc = 0

    迭代次数= 0

    对于范围(0,len(X_),batch_size)中的 i:

    迭代次数== 1

    b =我+ batch_size

    X_batch = torch.tensor(X_.iloc [i:b,:]。values).float()

    y_batch = torch.tensor(y_.iloc [i:b] .values)

    log_ps =模型(X_batch)

    损失=标准(log_ps,y_batch)

    Optimizer.zero_grad()

    loss.backward()

    Optimizer.step()

    running_loss + = loss.item()

    ps = torch.exp(log_ps)

    top_p,top_class = ps.topk(1,暗= 1)

    running_acc + =精度得分(y_batch,top_class)

    dev_loss = 0

    acc = 0

    使用 torch.no_grad():

    model.eval()

    log_dev =模型(X_dev_torch)

    dev_loss =条件(log_dev,y_dev_torch)

    ps_dev = torch.exp(log_dev)

    top_p,top_class_dev = ps_dev.topk(1,暗= 1)

    acc = precision_score(y_dev_torch,top_class_dev)

    model.train()

W
wizardforcel 已提交
724
    如果 e% 50 == 0 或 e == 1:
W
wizardforcel 已提交
725 726 727 728 729 730 731 732 733 734 735 736 737

    x_axis.append(e)

    train_losses.append(running_loss / iterations)

    dev_losses.append(dev_loss)

    train_acc.append(running_acc / iterations)

    dev_acc.append(acc)

    print(“ Epoch:{} / {} ..”“ .format(e,epochs),\

W
wizardforcel 已提交
738
    “训练损失:{:. 3f} ..” \
W
wizardforcel 已提交
739 740 741 742 743

    .format(running_loss / iterations),\

    “验证损失:{:. 3f} ..” .format(dev_loss),\

W
wizardforcel 已提交
744
    “训练准确率:{:. 3f} ..” \
W
wizardforcel 已提交
745 746 747

    .format(running_acc / iterations),\

W
wizardforcel 已提交
748
    “验证准确率:{:. 3f}”。format(acc))
W
wizardforcel 已提交
749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783

    注意

    可以在以前共享的 GitHub 存储库中找到此活动随附的 Jupyter Notebook。 在那里,您会发现对模型进行微调的各种尝试及其结果。 性能最佳的型号可以在笔记本电脑的末尾找到。

4.  Plot the loss and accuracy for both sets of data:

    注意

    请记住,此处显示的结果与您的结果不完全匹配。 这主要是由于训练网络时使用了改组功能。

    使用以下代码绘制损失:

    无花果= plt.figure(figsize =(15,5))

    plt.plot(x_axis,train_losses,label ='训练损失')

    plt.plot(x_axis,dev_losses,label ='验证损失')

    plt.legend(frameon = False,fontsize = 15)

    plt.show()

    运行前面的代码将显示以下图:

    ![Figure 3.17: A plot displaying the loss of the sets ](img/B15778_03_17.jpg)

    图 3.17:显示集合损失的图

    使用以下代码来绘制精度:

    无花果= plt.figure(figsize =(15,5))

    plt.plot(x_axis,train_acc,label =“训练精度”)

W
wizardforcel 已提交
784
    plt.plot(x_axis,dev_acc,label =“验证准确率”)
W
wizardforcel 已提交
785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809

    plt.legend(frameon = False,fontsize = 15)

    plt.show()

    运行前面的代码将显示以下图:

    ![Figure 3.18: A plot displaying the accuracy of the sets ](img/B15778_03_18.jpg)

    图 3.18:显示集合精度的图

5.  Using the best-performing model, perform a prediction over the testing set (which should not have been used during the fine-tuning process). Compare the prediction with the ground truth by calculating the accuracy of the model over this set:

    model.eval()

    test_pred =模型(X_test_torch)

    test_pred = torch.exp(test_pred)

    top_p,top_class_test = test_pred.topk(1,暗= 1)

    acc_test = precision_score(y_test_torch,top_class_test)

    打印(acc_test)

W
wizardforcel 已提交
810
    通过模型架构和此处定义的参数获得的精度应为 80% 左右。
W
wizardforcel 已提交
811 812 813

    注意

W
wizardforcel 已提交
814
    要访问此特定部分的源代码,请参考[这里](https://packt.live/2Bs42hh)。
W
wizardforcel 已提交
815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879

    本部分当前没有在线交互示例,需要在本地运行。

## 活动 3.03:使用模型

### 解决方案

1.  打开用于上一个活动的 Jupyter Notebook。
2.  Copy the class containing the architecture of your best-performing model and save it in a Python file. Make sure that you import PyTorch's required libraries and modules. Name it **final_model.py**.

    该文件应如下所示:

    ![Figure 3.19: A screenshot of final_model.py ](img/B15778_03_19.jpg)

    图 3.19:final_model.py 的屏幕截图

3.  In the Jupyter Notebook, save the best-performing model. Make sure to save the information pertaining to the input units, along with the parameters of the model. Name it **checkpoint.pth**:

    检查点= {“输入”:X_train.shape [1],\

    “ state_dict”:model.state_dict()}

    torch.save(检查点,“ checkpoint.pth”)

4.  打开一个新的 Jupyter Notebook。
5.  Import PyTorch, as well as the Python file we created in *Step 2*:

    进口火炬

    导入 final_model

6.  Create a function that loads the model:

    def load_model_checkpoint(path):

    检查点= torch.load(路径)

    模型= final_model.Classifier(checkpoint [“ input”])

    model.load_state_dict(checkpoint [“ state_dict”])

    退货模式

    模型= load_model_checkpoint(“ checkpoint.pth”)

7.  Perform a prediction by inputting the following tensor into your model:

    例子= torch.tensor([[0.0606,0.5000,0.3333,0.4828,\

    0.4000, 0.4000, 0.4000, 0.4000, \

    0.4000, 0.4000, 0.1651, 0.0869, \

    0.0980, 0.1825, 0.1054, 0.2807, \

    0.0016, 0.0000, 0.0033, 0.0027, \

    0.0031,0.0021]])。float()

    之前=模型(示例)

    pred = torch.exp(pred)

    top_p,top_class_test = pred.topk(1,暗= 1)

W
wizardforcel 已提交
880
    通过打印`top_class_test`,我们可以获得模型的预测,在这种情况下,该预测等于`1`(是)。
W
wizardforcel 已提交
881 882 883 884 885 886 887 888 889 890 891 892 893 894 895

8.  Convert the model using the JIT module:

    traced_script = torch.jit.trace(模型,例如\

    check_trace = False)

9.  Perform a prediction by inputting the same tensor as in *Step 7* to the traced script of your model:

    预测= traced_script(示例)

    预测= torch.exp(预测)

    top_p_2,top_class_test_2 = projection.topk(1,dim = 1)

W
wizardforcel 已提交
896
    通过打印`top_class_test_2`,我们从模型的跟踪脚本表示中获得了预测,该预测再次等于`1`(是)。
W
wizardforcel 已提交
897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951

10.  Open a new Jupyter Notebook and import the required libraries to create an API using Flask, as well as the libraries to load the saved model:

    进口烧瓶

    从烧瓶进口要求

    进口火炬

    导入 final_model

11.  Initialize the Flask app:

    app = flask.Flask(__ name__)

    app.config [“ DEBUG”] = True

12.  Define a function that loads the saved model and then instantiate the model:

    def load_model_checkpoint(path):

    检查点= torch.load(路径)

    模型= final_model.Classifier(checkpoint [“ input”])

    model.load_state_dict(checkpoint [“ state_dict”])

    退货模式

    模型= load_model_checkpoint(“ checkpoint.pth”)

13.  Define the route of the API to **/prediction** and set the method to **POST**. Then, define the function that will receive the **POST** data and feed it to the model to perform a prediction:

    @ app.route('/ prediction',methods = ['POST'])

    def definition():

    正文= request.get_json()

    示例= torch.tensor(body ['data'])。float()

    之前=模型(示例)

    pred = torch.exp(pred)

    _,top_class_test = pred.topk(1,暗= 1)

    top_class_test = top_class_test.numpy()

    return {“ status”:“ ok”,“ result”:int(top_class_test [0] [0])}

14.  Run the Flask app:

    app.run(debug = True,use_reloader = False)

W
wizardforcel 已提交
952
    使用为 API 开发而创建的平台 Postman,可以测试 API。 要向 Postman 提交成功的请求,标头的`*Content-Type`应当等于`application/json`。 结果输出应如下所示:
W
wizardforcel 已提交
953 954 955 956 957 958 959

![Figure 3.20: A screenshot of the app after running it ](img/B15778_03_13.jpg)

图 3.20:应用程序运行后的屏幕截图

注意

W
wizardforcel 已提交
960
要访问此特定部分的源代码,请参考[这里](https://packt.live/2NHkddn)
W
wizardforcel 已提交
961 962 963 964 965 966 967 968 969

本部分当前没有在线交互示例,需要在本地运行。

# 4.卷积神经网络

## 活动 4.01:针对图像分类问题构建 CNN

### 解决方案

W
wizardforcel 已提交
970
1.  导入所需的库。
W
wizardforcel 已提交
971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015

    将 numpy 导入为 np

    进口火炬

    从火炬进口 nn,乐观

    导入功能为 F 的 torch.nn。

    从 torchvision 导入数据集中

    导入 torchvision.transforms 作为转换

    从 torch.utils.data.sampler 导入 SubsetRandomSampler

    从 sklearn.metrics 导入 precision_score

    导入 matplotlib.pyplot 作为 plt

2.  Set the transformations to be performed on the data, which will be converting the data into tensors and normalizing the pixel values:

    变换= \

    transforms.Compose([[transforms.ToTensor(),\

    transforms.Normalize((0.5,0.5,0.5),\

    (0.5, 0.5, 0.5))])

3.  Set a batch size of 100 images and download both the training and testing data from the **CIFAR10** dataset:

    batch_size = 100

    train_data =数据集.CIFAR10('data',train = True,\

    download = True,\

    转换=转换)

    test_data =数据集.CIFAR10('data',train = False,\

    download = True,\

    转换=转换)

W
wizardforcel 已提交
1016
    前面的代码将下载可通过 PyTorch 的`Torchvision`软件包获得的训练和测试数据集。 根据上一步中定义的转换对数据集进行转换。
W
wizardforcel 已提交
1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033

4.  Using a validation size of 20%, define the training and validation sampler that will be used to divide the dataset into those two sets:

    dev_size = 0.2

    idx =列表(范围(len(train_data)))

    np.random.shuffle(idx)

    split_size = int(np.floor(dev_size * len(train_data)))

    train_idx,dev_idx = idx [split_size:],idx [:split_size]

    train_sampler = SubsetRandomSampler(train_idx)

    dev_sampler = SubsetRandomSampler(dev_idx)

W
wizardforcel 已提交
1034
    为了将训练集分为两组(训练和验证),为每个组定义了一个索引列表,然后可以使用`SubsetRandomSampler`函数对其进行随机采样。
W
wizardforcel 已提交
1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059

5.  Use the **DataLoader()** function to define the batches of each set of data to be used:

    train_loader = \

    torch.utils.data.DataLoader(train_data,\

    batch_size =批量大小,\

    sampler = train_sampler)

    dev_loader = \

    torch.utils.data.DataLoader(train_data,\

    batch_size =批量大小,\

    sampler = dev_sampler)

    test_loader = \

    torch.utils.data.DataLoader(test_data,\

    batch_size =批量大小)

W
wizardforcel 已提交
1060
    PyTorch 的`DataLoader`函数用于创建批量,这些批量将在开发过程的训练,验证和测试阶段馈送到模型中。
W
wizardforcel 已提交
1061 1062 1063 1064 1065 1066 1067 1068 1069

6.  Define the architecture of your network. Use the following information to do so:

    Conv1:卷积层,将彩色图像作为输入,并将其通过大小为 3 的 10 个滤镜。应将 padding 和 stride 都设置为 1。

    Conv2:一个卷积层,它将输入数据通过大小为 3 的 20 个过滤器传递。填充和跨距都应设置为 1。

    Conv3:一个卷积层,它将输入数据通过大小为 3 的 40 个过滤器传递。填充和跨距都应设置为 1。

W
wizardforcel 已提交
1070
    在每个卷积层之后使用 ReLU 激活函数。
W
wizardforcel 已提交
1071 1072 1073

    在每个卷积层之后使用池化层,滤镜大小和步幅为 2。

W
wizardforcel 已提交
1074
    展平图像后,使用掉落项设置为 20%。
W
wizardforcel 已提交
1075

W
wizardforcel 已提交
1076
    线性 1:一个全连接层,接收上一层的展平矩阵作为输入,并生成 100 个单位的输出。 为此层使用 ReLU 激活函数。 此处的辍学期限设置为 20%。
W
wizardforcel 已提交
1077

W
wizardforcel 已提交
1078
    Linear2:一个全连接层,可生成 10 个输出,每个类标签一个。 将`log_softmax`激活函数用于输出层:
W
wizardforcel 已提交
1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119

    CNN(nn.Module)类:

    def __init __():

    超级(CNN,自我).__ init __()

    self.conv1 = nn.Conv2d(3,10,3,1,1)

    self.conv2 = nn.Conv2d(10,20,3,1,1)

    self.conv3 = nn.Conv2d(20,40,3,1,1)

    self.pool = nn.MaxPool2d(2,2)

    self.linear1 = nn.Linear(40 * 4 * 4,100)

    self.linear2 = nn.Linear(100,10)

    self.dropout = nn.Dropout(0.2)

    def forward(self,x):

    x = self.pool(F.relu(self.conv1(x)))

    x = self.pool(F.relu(self.conv2(x)))

    x = self.pool(F.relu(self.conv3(x)))

    x = x.view(-1,40 * 4 * 4)

    x = self.dropout(x)

    x = F.relu(self.linear1(x))

    x = self.dropout(x)

    x = F.log_softmax(self.linear2(x),dim = 1)

    返回 x

W
wizardforcel 已提交
1120
    前面的代码段包含一个定义了网络架构的类(`__init__`方法),以及在信息正向传递过程中所遵循的步骤(`forward`方法)。
W
wizardforcel 已提交
1121

W
wizardforcel 已提交
1122
7.  Define all of the parameters that are required to train your model. Set the number of epochs to`50`:
W
wizardforcel 已提交
1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157

    型号= CNN()

    loss_function = nn.NLLLoss()

    优化程序= optim.Adam(model.parameters(),lr = 0.001)

    时代= 50

    我们为此练习选择的优化器是 Adam。 同样,负对数似然率用作损失函数,如本书前一章所述。

    如果您的计算机具有可用的 GPU,则应按以下步骤完成模型的实例化:

    型号= CNN()。to(“ cuda”)

8.  Train your network and be sure to save the values for the loss and accuracy of both the training and validation sets:

    train_losses,dev_losses,train_acc,dev_acc = [],[],[],[]

    x_axis = []

    #循环遍历

    对于范围(1,历元+1)中的 e:

    损失= 0

    acc = 0

    迭代次数= 0

    model.train()

    """

W
wizardforcel 已提交
1158
    For 遍历批量(使用创建
W
wizardforcel 已提交
1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195

    火车装载者)

    """

    对于数据,在 train_loader 中定位:

    迭代次数== 1

    #训练数据的前后传递

    pred =模型(数据)

    损失= loss_function(pred,目标)

    Optimizer.zero_grad()

    loss.backward()

    Optimizer.step()

    损失+ = loss.item()

    p = torch.exp(pred)

    top_p,top_class = p.topk(1,暗= 1)

    acc + = precision_score(target,top_class)

    dev_losss = 0

    dev_accs = 0

    iter_2 = 0

    #验证给定时期的模型

W
wizardforcel 已提交
1196
    如果 e% 5 == 0 或 e == 1:
W
wizardforcel 已提交
1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229

    x_axis.append(e)

    使用 torch.no_grad():

    model.eval()

    """

    用于循环遍历

    验证集

    """

    对于 dev_loader 中的 data_dev,target_dev:

    iter_2 + = 1

    dev_pred =模型(data_dev)

    dev_loss = loss_function(dev_pred,target_dev)

    dev_losss + = dev_loss.item()

    dev_p = torch.exp(dev_pred)

    top_p,dev_top_class = dev_p.topk(1,暗= 1)

    dev_accs + = precision_score(target_dev,\

    dev_top_class)

W
wizardforcel 已提交
1230
    #损失和准确率将附加打印
W
wizardforcel 已提交
1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241

    train_losses.append(损失/迭代)

    dev_losses.append(dev_losss / iter_2)

    train_acc.append(acc /迭代)

    dev_acc.append(dev_accs / iter_2)

    print(“ Epoch:{} / {} ..”“ .format(e,epochs),\

W
wizardforcel 已提交
1242
    “训练损失:{:. 3f} ..” \
W
wizardforcel 已提交
1243 1244 1245 1246 1247 1248 1249

    .format(损失/迭代),\

    “验证损失:{:. 3f} ..” \

    .format(dev_losss / iter_2),\

W
wizardforcel 已提交
1250
    “训练准确率:{:. 3f} ..” \
W
wizardforcel 已提交
1251 1252 1253

    .format(acc / iterations),\

W
wizardforcel 已提交
1254
    “验证准确率:{:. 3f}” \
W
wizardforcel 已提交
1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277

    .format(dev_accs / iter_2))

    如果您的计算机具有可用的 GPU,则对前面的代码进行一些修改,如下所示:

    train_losses,dev_losses,train_acc,dev_acc = [],[],[],[]

    x_axis = []

    #循环遍历

    对于范围(1,历元+1)中的 e:

    损失= 0

    acc = 0

    迭代次数= 0

    model.train()

    """

W
wizardforcel 已提交
1278
    循环遍历批量
W
wizardforcel 已提交
1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317

    (使用火车装载程序创建)

    """

    对于数据,在 train_loader 中定位:

    迭代次数== 1

    #训练数据的前后传递

    pred =模型(data.to(“ cuda”))

    损失= loss_function(pred,target.to(“ cuda”))

    Optimizer.zero_grad()

    loss.backward()

    Optimizer.step()

    损失+ = loss.item()

    p = torch.exp(pred)

    top_p,top_class = p.topk(1,暗= 1)

    acc + = precision_score(target.to(“ cpu”),\

    top_class.to(“ cpu”))

    dev_losss = 0

    dev_accs = 0

    iter_2 = 0

    #验证给定时期的模型

W
wizardforcel 已提交
1318
    如果 e% 5 == 0 或 e == 1:
W
wizardforcel 已提交
1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355

    x_axis.append(e)

    使用 torch.no_grad():

    model.eval()

    """

    用于循环遍历

    验证集

    """

    对于 dev_loader 中的 data_dev,target_dev:

    iter_2 + = 1

    dev_pred =模型(data_dev.to(“奇迹”))

    dev_loss = loss_function(dev_pred,\

    target_dev.to(“ cuda”))

    dev_losss + = dev_loss.item()

    dev_p = torch.exp(dev_pred)

    top_p,dev_top_class = dev_p.topk(1,暗= 1)

    dev_accs + = \

    precision_score(target_dev.to(“ cpu”),\

    dev_top_class.to(“ cpu”))

W
wizardforcel 已提交
1356
    #损失和准确率将附加打印
W
wizardforcel 已提交
1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367

    train_losses.append(损失/迭代)

    dev_losses.append(dev_losss / iter_2)

    train_acc.append(acc /迭代)

    dev_acc.append(dev_accs / iter_2)

    print(“ Epoch:{} / {} ..”“ .format(e,epochs),\

W
wizardforcel 已提交
1368
    “训练损失:{:. 3f} ..” \
W
wizardforcel 已提交
1369 1370 1371 1372 1373 1374 1375

    .format(损失/迭代),\

    “验证损失:{:. 3f} ..” \

    .format(dev_losss / iter_2),\

W
wizardforcel 已提交
1376
    “训练准确率:{:. 3f} ..” \
W
wizardforcel 已提交
1377 1378 1379

    .format(acc / iterations),\

W
wizardforcel 已提交
1380
    “验证准确率:{:. 3f}” \
W
wizardforcel 已提交
1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403

    .format(dev_accs / iter_2))

9.  Plot the loss and accuracy of both sets. To plot the loss, use the following code:

    plt.plot(x_axis,train_losses,label ='训练损失')

    plt.plot(x_axis,dev_losses,label ='验证损失')

    plt.legend(frameon = False)

    plt.show()

    结果图应类似于以下内容:

    ![Figure 4.23: Resulting plot showing the loss of the sets ](img/B15778_04_23.jpg)

    图 4.23:结果图显示了集合的丢失

    要绘制精度,请使用以下代码:

    plt.plot(x_axis,train_acc,label =“训练精度”)

W
wizardforcel 已提交
1404
    plt.plot(x_axis,dev_acc,label =“验证准确率”)
W
wizardforcel 已提交
1405 1406 1407 1408 1409 1410 1411 1412 1413

    plt.legend(frameon = False)

    plt.show()

    该图应类似于以下内容:

    ![Figure 4.24: Resulting plot showing the accuracy of the sets ](img/B15778_04_24.jpg)

W
wizardforcel 已提交
1414
    图 4.24:结果图显示了集合的准确率
W
wizardforcel 已提交
1415

W
wizardforcel 已提交
1416
    可以看出,在第 15 个时期之后,过拟合开始影响模型。
W
wizardforcel 已提交
1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439

10.  Check the model's accuracy on the testing set:

    model.eval()

    iter_3 = 0

    acc_test = 0

    对于 test_loader 中的 data_test 和 target_test:

    iter_3 + = 1

    test_pred =模型(data_test)

    test_pred = torch.exp(test_pred)

    top_p,top_class_test = test_pred.topk(1,暗= 1)

    acc_test + =准确度得分(target_test,top_class_test)

    打印(acc_test / iter_3)

W
wizardforcel 已提交
1440
    使用我们之前创建的数据加载器,可以对测试集数据进行图像分类,以估计模型在看不见数据上的准确率。
W
wizardforcel 已提交
1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465

    如果您的计算机具有可用的 GPU,则对前面的代码进行一些修改,如下所示:

    model.eval()

    iter_3 = 0

    acc_test = 0

    对于 test_loader 中的 data_test 和 target_test:

    iter_3 + = 1

    test_pred =模型(data_test.to(“ cuda”))

    test_pred = torch.exp(test_pred)

    top_p,top_class_test = test_pred.topk(1,暗= 1)

    acc_test + = precision_score(target_test .to(“ cpu”),\

    top_class_test .to(“ cpu”))

    打印(acc_test / iter_3)

W
wizardforcel 已提交
1466
    测试集的准确率与其他两组所达到的准确率非常相似,这意味着该模型能够对看不见的数据表现出同样出色的性能。 它应该在 72% 左右。
W
wizardforcel 已提交
1467 1468 1469

    注意

W
wizardforcel 已提交
1470
    要访问此特定部分的源代码,请参考[这里](https://packt.live/3gjvWuV)。
W
wizardforcel 已提交
1471 1472 1473

    本部分当前没有在线交互示例,需要在本地运行。

W
wizardforcel 已提交
1474
    要访问此源代码的 GPU 版本,请参考[这里](https://packt.live/2BUGjGF)。 此版本的源代码无法作为在线交互示例使用,需要通过 GPU 设置在本地运行。
W
wizardforcel 已提交
1475 1476 1477 1478 1479 1480 1481

## 活动 4.02:实施数据增强

### 解决方案

1.  Duplicate the notebook from the previous activity.

W
wizardforcel 已提交
1482
    为了完成此活动,按照以下步骤,除了修改`tranforms`值之外,不会更改任何代码。
W
wizardforcel 已提交
1483 1484 1485

2.  Change the definition of the **transform** variable so that it includes, in addition to normalizing and converting the data into tensors, the following transformations:

W
wizardforcel 已提交
1486
    对于训练/验证集,请使用`RandomHorizo​​ntalFlip`函数,其概率为 50% (`0.5`),并使用`RandomGrayscale`函数,其概率为 10% (`0.1`)。
W
wizardforcel 已提交
1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515

    对于测试集,请勿添加任何其他转换:

    变换= \

    {“火车”:transforms.Compose([\

    transforms.RandomHorizo​​ntalFlip(0.5),\

    transforms.RandomGrayscale(0.1),\

    transforms.ToTensor(),\

    transforms.Normalize((0.5,0.5,0.5),\

    (0.5, 0.5, 0.5))]),\

    “ test”:transforms.Compose([\

    transforms.ToTensor(),\

    transforms.Normalize((0.5,0.5,0.5),\

    (0.5, 0.5, 0.5))])}

3.  Train the model for 100 epochs.

    如果您的计算机具有可用的 GPU,请确保使用代码的 GPU 版本来训练模型。

W
wizardforcel 已提交
1516
    在训练和验证集上得出的损失和准确率图应与此处显示的图相似:
W
wizardforcel 已提交
1517 1518 1519 1520 1521 1522 1523

    ![Figure 4.25: Resulting plot showing the loss of the sets ](img/B15778_04_25.jpg)

    图 4.25:结果图显示了集合的丢失

    ![Figure 4.26: Resulting plot showing the accuracy of the sets ](img/B15778_04_26.jpg)

W
wizardforcel 已提交
1524
    图 4.26:结果图显示了集合的准确率
W
wizardforcel 已提交
1525

W
wizardforcel 已提交
1526
    通过添加数据扩充,可以改善模型的性能,并减少发生的过拟合。
W
wizardforcel 已提交
1527 1528 1529

4.  Calculate the accuracy of the resulting model on the testing set.

W
wizardforcel 已提交
1530
    该模型在测试设备上的性能提高了约 75%。
W
wizardforcel 已提交
1531 1532 1533

    注意

W
wizardforcel 已提交
1534
    要访问此特定部分的源代码,请参考[这里](https://packt.live/3ePcAND)。
W
wizardforcel 已提交
1535 1536 1537

    本部分当前没有在线交互示例,需要在本地运行。

W
wizardforcel 已提交
1538
    要访问此源代码的 GPU 版本,请参考[这里](https://packt.live/38jpq4g)。 此版本的源代码无法作为在线交互示例使用,需要通过 GPU 设置在本地运行。
W
wizardforcel 已提交
1539 1540 1541 1542 1543 1544 1545

## 活动 4.03:实现批量标准化

### 解决方案

1.  Duplicate the notebook from the previous activity.

W
wizardforcel 已提交
1546
    要完成此活动,按照以下步骤,除了在网络架构中添加一些层之外,不会更改任何代码。
W
wizardforcel 已提交
1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601

2.  Add batch normalization to each convolutional layer, as well as to the first fully connected layer.

    网络的最终架构应如下:

    CNN(nn.Module)类:

    def __init __():

    超级(净,自我).__ init __()

    self.conv1 = nn.Conv2d(3,10,3,1,1)

    self.norm1 = nn.BatchNorm2d(10)

    self.conv2 = nn.Conv2d(10,20,3,1,1)

    self.norm2 = nn.BatchNorm2d(20)

    self.conv3 = nn.Conv2d(20,40,3,1,1)

    self.norm3 = nn.BatchNorm2d(40)

    self.pool = nn.MaxPool2d(2,2)

    self.linear1 = nn.Linear(40 * 4 * 4,100)

    self.norm4 = nn.BatchNorm1d(100)

    self.linear2 = nn.Linear(100,10)

    self.dropout = nn.Dropout(0.2)

    def forward(self,x):

    x = self.pool(self.norm1(F.relu(self.conv1(x))))

    x = self.pool(self.norm2(F.relu(self.conv2(x))))

    x = self.pool(self.norm3(F.relu(self.conv3(x))))

    x = x.view(-1,40 * 4 * 4)

    x = self.dropout(x)

    x = self.norm4(F.relu(self.linear1(x)))

    x = self.dropout(x)

    x = F.log_softmax(self.linear2(x),dim = 1)

    返回 x

3.  Train the model for 100 epochs.

W
wizardforcel 已提交
1602
    如果您的计算机具有可用的 GPU,请确保使用代码的 GPU 版本来训练模型。 训练和验证集的损失和准确率的结果图应类似于此处所示:
W
wizardforcel 已提交
1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615

    ![Figure 4.27: Resulting plot showing the loss of the sets ](img/B15778_04_27.jpg)

    图 4.27:结果图显示集合的丢失

    ![Figure 4.28: Resulting plot showing the loss of the sets ](img/B15778_04_28.jpg)

    图 4.28:结果图显示集合的丢失

    尽管过拟合再次引入了模型,但是我们可以看到两组的性能都有所提高。

    注意

W
wizardforcel 已提交
1616
    尽管本章未对此进行探讨,但理想的步骤是为网络架构添加辍学以减少高方差。 随意尝试一下,看看您是否能够进一步提高性能。
W
wizardforcel 已提交
1617 1618 1619

4.  Calculate the accuracy of the resulting model on the testing set.

W
wizardforcel 已提交
1620
    该模型在测试设备上的性能已提高了约 78%。
W
wizardforcel 已提交
1621 1622 1623

    注意

W
wizardforcel 已提交
1624
    要访问此特定部分的源代码,请参考[这里](https://packt.live/31sSR2G)。
W
wizardforcel 已提交
1625 1626 1627

    本部分当前没有在线交互示例,需要在本地运行。

W
wizardforcel 已提交
1628
    要访问此源代码的 GPU 版本,请参考[这里](https://packt.live/3eVgp4g)。 此版本的源代码无法作为在线交互示例使用,需要通过 GPU 设置在本地运行。
W
wizardforcel 已提交
1629 1630 1631 1632 1633 1634 1635

# 5.样式转移

## 活动 5.01:执行样式转换

### 解决方案

W
wizardforcel 已提交
1636
1.  导入所需的库。
W
wizardforcel 已提交
1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649

    将 numpy 导入为 np

    进口火炬

    从火炬进口 nn,乐观

    从 PIL 导入图片

    导入 matplotlib.pyplot 作为 plt

    从 torchvision 导入转换,模型

W
wizardforcel 已提交
1650
    如果您的计算机具有可用的 GPU,请确保定义一个名为`device`的变量,该变量将有助于为 GPU 分配一些变量,如下所示:
W
wizardforcel 已提交
1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787

    device = "cuda"

2.  Specify the transformations to be performed over the input images. Be sure to resize them to the same size, convert them into tensors, and normalize them:

    尺寸= 224

    加载程序= \

    transforms.Compose([transforms.Resize(imsize),\

    transforms.ToTensor(),\

    transforms.Normalize((0.485,0.456,0.406),\

    (0.229, 0.224, 0.225))])

3.  Define an image loader function. It should open the image and load it. Call the image loader function to load both input images:

    def image_loader(图片名称):

    图片= Image.open(图片名称)

    图片=加载程序(图片)。取消压缩(0)

    返回图片

    content_img = image_loader(“ images / landscape.jpg”)

    style_img = image_loader(“ images / monet.jpg”)

    如果您的计算机有可用的 GPU,请改用以下代码段:

    def image_loader(图片名称):

    图片= Image.open(图片名称)

    图片=加载程序(图片)。取消压缩(0)

    返回图片

    content_img = image_loader(“ images / landscape.jpg”)。to(device)

    style_img = image_loader(“ images / monet.jpg”)。to(device)

4.  To be able to display the images, set the transformations to revert the normalization of the images and to convert the tensors into **PIL** images:

    卸载程序= transforms.Compose([\

    transforms.Normalize((-0.485 / 0.229,\

    -0.456/0.224, \

    -0.406/0.225), \

    (1/0.229, 1/0.224, 1/0.225)),\

    transforms.ToPILImage()])

5.  Create a function (**tensor2image**) that's capable of performing the previous transformation over tensors. Call the function for both images and plot the results:

    def tensor2image(张量):

    图片= tensor.clone()

    图片= image.squeeze(0)

    图片=卸载程序(图片)

    返回图片

    plt.figure()

    plt.imshow(tensor2image(content_img))

    plt.title(“内容图片”)

    plt.show()

    plt.figure()

    plt.imshow(tensor2image(style_img))

    plt.title(“样式图片”)

    plt.show()

    如果您的计算机有可用的 GPU,请改用以下代码段:

    def tensor2image(张量):

    图片= tensor.to(“ cpu”)。clone()

    图片= image.squeeze(0)

    图片=卸载程序(图片)

    返回图片

    plt.figure()

    plt.imshow(tensor2image(content_img))

    plt.title(“内容图片”)

    plt.show()

    plt.figure()

    plt.imshow(tensor2image(style_img))

    plt.title(“样式图片”)

    plt.show()

6.  Load the VGG-19 model:

    模型= models.vgg19(pretrained = True)。功能

    对于 model.parameters()中的参数:

    param.requires_grad_(False)

    如果您的计算机有可用的 GPU,请确保将包含模型的变量分配给 GPU,如下所示:

    model.to(设备)

7.  Create a dictionary for mapping the index of the relevant layers (keys) to a name (values). Then, create a function to extract the feature maps of the relevant layers. Use them to extract the features of both input images.

    以下函数应为每个相关层提取给定图像的特征:

    related_layers = {'0':'conv1_1','5':'conv2_1',\

    '10':'conv3_1','19':'conv4_1',\

    '21':'conv4_2','28':'conv5_1'}

W
wizardforcel 已提交
1788
    def features_extractor(x,模型,层):
W
wizardforcel 已提交
1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815

    功能= {}

    用于索引,位于 model._modules.items()中的层:

    x =层(x)

    如果层索引:

    features [layers [index]] = x

    返回特征

    接下来,应该为**内容**和**样式**图像调用该函数:

    content_features = features_extractor(content_img,\

    型号,

    related_layers)

    style_features = features_extractor(style_img,model,\

    related_layers)

8.  Calculate the gram matrix for the style features. Also, create the initial target image.

W
wizardforcel 已提交
1816
    以下代码段为用于提取样式特征的每个层创建了 gram 矩阵:
W
wizardforcel 已提交
1817 1818 1819 1820 1821

    style_grams = {}

    对于我在 style_features 中:

W
wizardforcel 已提交
1822
    层= style_features [i]
W
wizardforcel 已提交
1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853

    _,d1,d2,d3 = layer.shape

    功能= layer.view(d1,d2 * d3)

    克= torch.mm(features,features.t())

    style_grams [i] =克

    接下来,创建初始目标图像作为内容图像的克隆:

    target_img = content_img.clone()。requires_grad_(正确)

    如果您的计算机有可用的 GPU,请改用以下代码段:

    target_img = content_img.clone()。\

    require_grad_(True).to(设备)

9.  Set the weights for different style layers, as well as the weights for the content and style losses:

    style_weights = {'conv1_1':1.,'conv2_1':0.8,\

    'conv3_1':0.6,'conv4_1':0.4,\

    'conv5_1':0.2}

    阿尔法= 1

    Beta = 1e5

W
wizardforcel 已提交
1854
10.  Run the model for 500 iterations. Define the Adam optimization algorithm before starting to train the model, using`0.001`as the learning rate:
W
wizardforcel 已提交
1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867

    注意

    为了获得本书所示的最终目标图像,该代码运行了 5,000 次迭代,而没有 GPU 则需要很长时间才能运行。 但是,要欣赏输出图像中开始发生的更改,尽管鼓励您测试不同的训练时间,但只需运行 500 次迭代就足够了。

    print_statement = 500

    优化程序= torch.optim.Adam([target_img],lr = 0.001)

    迭代= 5000

    对于范围(1,迭代+1)中的 i:

W
wizardforcel 已提交
1868
    #提取所有相关层的特征
W
wizardforcel 已提交
1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883

    target_features = features_extractor(target_img,模型,\

    related_layers)

    #计算内容损失

    content_loss = torch.mean((target_features ['conv4_2'] \

    -content_features ['conv4_2'])** 2)

    #遍历所有样式层

    style_losses = 0

W
wizardforcel 已提交
1884
    用于 style_weights 中的层:
W
wizardforcel 已提交
1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899

    #为该层创建语法矩阵

    target_feature = target_features [layer]

    _,d1,d2,d3 = target_feature.shape

    target_reshaped = target_feature.view(d1,d2 * d3)

    target_gram = torch.mm(target_reshaped,\

    target_reshaped.t())

    style_gram = style_grams [layer]

W
wizardforcel 已提交
1900
    #计算该层的样式损失
W
wizardforcel 已提交
1901 1902 1903 1904 1905 1906 1907

    style_loss = style_weights [layer] * \

    torch.mean((target_gram-\

    style_gram)** 2)

W
wizardforcel 已提交
1908
    #计算所有层的样式丢失
W
wizardforcel 已提交
1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925

    style_losses + = style_loss /(d1 * d2 * d3)

    #计算总损失

    total_loss = alpha * content_loss + beta * style_losses

    #执行反向传播

    Optimizer.zero_grad()

    total_loss.backward()

    Optimizer.step()

    #打印目标图像

W
wizardforcel 已提交
1926
    如果 i% print_statement == 0 或 i == 1:
W
wizardforcel 已提交
1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955

    print('Total loss:',total_loss.item())

    plt.imshow(tensor2image(target_img))

    plt.show()

11.  Plot the **content**, **style**, and **target** images to compare the results:

    图,(ax1,ax2,ax3)= plt.subplots(1,3,图大小=(15,5))

    ax1.imshow(tensor2image(content_img))

    ax2.imshow(tensor2image(target_img))

    ax3.imshow(tensor2image(style_img))

    plt.show()

    从此代码段派生的图应类似于此处显示的图:

![Figure 5.11: Output plots ](img/B15778_05_11.jpg)

图 5.11:输出图

注意

要查看 高质量彩色图像,请访问本书的 GitHub 存储库,网址为 https://packt.live/2KcORcw。

W
wizardforcel 已提交
1956
要访问此特定部分的源代码,请参考[这里](https://packt.live/2BZj91B)
W
wizardforcel 已提交
1957 1958 1959

本部分当前没有在线交互示例,需要在本地运行。

W
wizardforcel 已提交
1960
要访问此源代码的 GPU 版本,请参考[这里](https://packt.live/3eNfvqc)。 此版本的源代码无法作为在线交互示例使用,需要通过 GPU 设置在本地运行。
W
wizardforcel 已提交
1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991

# 6.使用 RNN 分析数据序列

## 活动 6.01:使用简单的 RNN 进行时间序列预测

### 解决方案

1.  Import the required libraries, as follows:

    将熊猫作为 pd 导入

    导入 matplotlib.pyplot 作为 plt

    进口火炬

    从火炬进口 nn,乐观

2.  Load the dataset and then slice it so that it contains all the rows but only the columns from index 1 to 52:

    数据= pd.read_csv(“ Sales_Transactions_Dataset_Weekly.csv”)

    数据= data.iloc [:,1:53]

    data.head()

    输出如下:

    ![Figure 6.26: Displaying dataset for columns from index 1 to 52 ](img/B15778_06_26.jpg)

    图 6.26:显示索引 1 到 52 列的数据集

W
wizardforcel 已提交
1992
3.  Plot the weekly sales transactions of five randomly chosen products from the entire dataset. Use a random seed of`0`when performing random sampling in order to achieve the same results as in the current activity:
W
wizardforcel 已提交
1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019

    plot_data = data.sample(5,random_state = 0)

    x =范围(1,53)

    plt.figure(figsize =(10,5))

    对于我,在 plot_data.iterrows()中行:

    plt.plot(x,行)

    plt.legend(plot_data.index)

    plt.xlabel(“周”)

    plt.ylabel(“每件商品的销售交易”)

    plt.show()

    结果图应如下所示:

    ![Figure 6.27: Plot of the output ](img/B15778_06_27.jpg)

    图 6.27:输出图

4.  Create the **inputs** and **targets** variables that will be fed to the network to create the model. These variables should be of the same shape and be converted into PyTorch tensors.

W
wizardforcel 已提交
2020
    `input`变量应包含除上周外的所有星期的所有产品数据,因为模型的目的是预测最后一周。
W
wizardforcel 已提交
2021

W
wizardforcel 已提交
2022
    `target`变量应比`input`变量领先一步; 也就是说,`target`变量的第一个值应该是输入变量中的第二个,依此类推,直到`target`变量的最后一个值(应该是 被留在`input`变量之外):
W
wizardforcel 已提交
2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035

    data_train = data.iloc [:,:-1]

    输入=火炬。张量(data_train.values)。取消挤压(1)

    目标= data_train.shift(-1,axis =“ columns”,\

    fill_value = data.iloc [:,-1])\

    .astype(dtype =“ float32”)

    目标=火炬。张量(targets.values)

W
wizardforcel 已提交
2036
5.  Create a class containing the architecture of the network. Note that the output size of the fully connected layer should be`1`:
W
wizardforcel 已提交
2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061

    RNN 类(nn.Module):

    def __init __(self,input_size,hidden_​​size,num_layers):

    super().__ init __()

    self.hidden_​​size = hidden_​​size

    self.rnn = nn.RNN(input_size,hidden_​​size,\

    num_layers,batch_first = True)

    self.output = nn.Linear(hidden_​​size,1)

    def forward(自我,x,隐藏):

    out,隐藏= self.rnn(x,隐藏)

    out = out.view(-1,self.hidden_​​size)

    out = self.output(输出)

    返回,隐藏

W
wizardforcel 已提交
2062
    与之前的活动一样,该类包含`__init__`方法以及网络架构,以及`forward`方法,该方法确定信息在各层之间的流动。
W
wizardforcel 已提交
2063

W
wizardforcel 已提交
2064
6.  Instantiate the **class** function containing the model. Feed the input size, the number of neurons in each recurrent layer (`10`), and the number of recurrent layers (`1`):
W
wizardforcel 已提交
2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091

    模型= RNN(data_train.shape [1],10,1)

    模型

    运行前面的代码将显示以下输出:

    RNN(

    (rnn):RNN(51、10,batch_first =真)

    (输出):线性(in_features = 10,out_features = 1,bias = True)

    )

7.  Define a loss function, an optimization algorithm, and the number of epochs to train the network. Use the MSE loss function, the Adam optimizer, and 10,000 epochs to do this:

    loss_function = nn.MSELoss()

    优化程序= optim.Adam(model.parameters(),lr = 0.001)

    纪元= 10000

8.  Use a **for** loop to perform the training process by going through all the epochs. In each epoch, a prediction must be made, along with the subsequent calculation of the loss function and the optimization of the parameters of the network. Save the loss of each of the epochs:

    注意

W
wizardforcel 已提交
2092
    考虑到没有批量用于遍历数据集,`hidden`量实际上并未在批量之间传递(而是在处理序列的每个元素时使用隐藏状态),但是 为了清楚起见,它留在这里。
W
wizardforcel 已提交
2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113

    损失= []

    对于范围(1,纪元+1)中的 i:

    隐藏=无

    pred,hidden =模型(输入,隐藏)

    target = target [:,-1] .unsqueeze(1)

    损失= loss_function(目标,pred)

    Optimizer.zero_grad()

    loss.backward()

    Optimizer.step()

    loss.append(loss.item())

W
wizardforcel 已提交
2114
    如果 i% 1000 == 0:
W
wizardforcel 已提交
2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187

    print(“ epoch:”,i,“ = ...损失函数:”,损失[-1])

    输出应如下所示:

    时代:1000 ...损失函数:58.48879623413086

    时代:2000 ...损失函数:24.934917449951172

    时代:3000 ...损失函数:13.247632026672363

    时代:4000 ...损失函数:9.884735107421875

    时代:5000 ...损失函数:8.778228759765625

    时代:6000 ...损失函数:8.025042533874512

    时代:7000 ...损失函数:7.622503757476807

    时代:8000 ...损失函数:7.4796295166015625

    时代:9000 ...损失函数:7.351718902587891

    时代:10000 ...损失函数:7.311776161193848

9.  Plot the losses of all epochs, as follows:

    x_range =范围(len(损失))

    plt.plot(x_range,损失)

    plt.xlabel(“时代”)

    plt.ylabel(“损失函数”)

    plt.show()

    结果图应如下所示:

    ![Figure 6.28: Plot displaying the losses of all epochs ](img/B15778_06_28.jpg)

    图 6.28:显示所有时期的损失的图

10.  Using a scatter plot, display the predictions that were obtained in the last epoch of the training process against the ground truth values (that is, the sales transactions of the last week):

    x_range =范围(len(数据))

    目标= data.iloc [:,-1] .values.reshape(len(data),1)

    plt.figure(figsize =(15,5))

    plt.scatter(x_range [:20],target [:20])

    plt.scatter(x_range [:20],pred.detach()。numpy()[:20])

    plt.legend([[地面真理],“预测”])

    plt.xlabel(“产品”)

    plt.ylabel(“销售交易”)

    plt.xticks(范围(0,20))

    plt.show()

    最终图应如下所示:

![Figure 6.29: Scatter plot displaying predictions ](img/B15778_06_29.jpg)

图 6.29:显示预测的散点图

注意

W
wizardforcel 已提交
2188
要访问此特定部分的源代码,请参考[这里](https://packt.live/2BqDWvg)
W
wizardforcel 已提交
2189

W
wizardforcel 已提交
2190
您也可以通过[这里](https://packt.live/3ihPgKB)在线运行此示例。 您必须执行整个笔记本才能获得所需的结果。
W
wizardforcel 已提交
2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251

## 活动 6.02:使用 LSTM 网络生成文本

### 解决方案

1.  Import the required libraries, as follows:

    导入数学

    将 numpy 导入为 np

    导入 matplotlib.pyplot 作为 plt

    进口火炬

    从火炬进口 nn,乐观

    导入功能为 F 的 torch.nn。

2.  Open and read the text from *Alice in Wonderland* into the notebook. Print an extract of the first 50 characters and the total length of the text file:

    使用 open('alice.txt' ,'r',encoding ='latin1')作为 f:

    数据= f.read()

    print(“ Extract:”,data [:50])

    print(“ Length:”,len(data))

3.  Create a variable containing a list of the unduplicated characters in your dataset. Then, create a dictionary that maps each character to an integer, where the characters will be the keys and the integers will be the values:

    字符=列表(设置(数据))

    indexer = {char:枚举(chars)中(index,char)的索引}

    输出应如下所示:

    摘录:爱丽丝开始对坐 b 感到非常厌倦

    长度:145178

4.  Encode each letter of your dataset to its paired integer. Print the first 50 encoded characters and the total length of the encoded version of your dataset:

    indexed_data = []

    对于 c 在数据中:

    indexed_data.append(indexer [c])

    print(“ Indexed extract:”,indexed_data [:50])

    print(“ Length:”,len(indexed_data))

    输出如下:

    索引提取物:[51、52、29、38、28、25、11、59、39、25、16、53、2、26、26、1、26、2、25、56、60、25, 2、53、56、25、23、53、7、45、25、56、1、7、53、13、25、60、14、25、39、1、56、56、1、26、2 25、16]

    长度:145178

5.  Create a function that takes in a batch and encodes it as a one-hot matrix:

W
wizardforcel 已提交
2252
    def index2onehot(批量):
W
wizardforcel 已提交
2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267

    batch_flatten = batch.flatten()

    onehot_flat = np.zeros(((batch.shape [0] \

    * batch.shape [1],len(indexer)))

    onehot_flat [range(len(batch_flatten)),batch_flatten] = 1

    onehot = onehot_flat.reshape((batch.shape [0],\

    batch.shape [1],-1))

    归还

W
wizardforcel 已提交
2268
    此函数采用二维矩阵并将其展平。 接下来,它创建一个平坦矩阵的形状和包含字母的字典长度的零填充矩阵(在“步骤 3”中创建)。 接下来,它用一个字符填充对应于批量中每个字符的字母。 最后,它对矩阵进行整形以使其为三维。
W
wizardforcel 已提交
2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315

6.  Create a class that defines the architecture of the network. This class should contain an additional function that initializes the states of the LSTM layers:

    LSTM(nn.Module)类:

    def __init __(self,char_length,hidden_​​size,n_layers):

    super().__ init __()

    self.hidden_​​size = hidden_​​size

    self.n_layers = n_layers

    self.lstm = nn.LSTM(char_length,hidden_​​size,\

    n_layers,batch_first = True)

    self.output = nn.Linear(hidden_​​size,char_length)

    def forward(自我,x,状态):

    出,状态= self.lstm(x,状态)

    out = out.contiguous()。view(-1,self.hidden_​​size)

    out = self.output(输出)

    返回状态

    def init_states(self,batch_size):

    隐藏= next(self.parameters())\

    .data.new(self.n_layers,batch_size,\

    self.hidden_​​size).zero_()

    单元格= next(self.parameters())\

    .data.new(self.n_layers,batch_size,\

    self.hidden_​​size).zero_()

    状态=(隐藏的单元格)

    返回状态

W
wizardforcel 已提交
2316
    此类包含`__init__`方法(其中定义了网络的架构),`forward`方法(用于确定通过层的数据流)以及`init_state`用零初始化隐藏状态和单元状态的方法。
W
wizardforcel 已提交
2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335

7.  Determine the number of batches to be created out of your dataset, bearing in mind that each batch should contain 100 sequences, each with a length of 50\. Next, split the encoded data into 100 sequences:

    #每批序列​​数

    n_seq = 100

    seq_length = 50

    n_batches = math.floor(len(indexed_data)\

    / n_seq / seq_length)

    total_length = n_seq * seq_length * n_batches

    x = indexed_data [:total_length]

    x = np.array(x).reshape(([ n_seq,-1))

W
wizardforcel 已提交
2336
8.  Instantiate your model by using`256`as the number of hidden units for a total of two recurrent layers:
W
wizardforcel 已提交
2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355

    模型= LSTM(仅(字符),256、2)

    模型

    运行前面的代码将显示以下输出:

    LSTM(

    (lstm):LSTM(70,256,num_layers = 2,batch_first = True)

    (输出):线性(in_features = 256,out_features = 70,bias = True)

    )

    如果您的计算机有可用的 GPU,请确保使用以下代码片段将模型分配给 GPU:

    模型= LSTM(len(chars),256,2).to(“ cuda”)

W
wizardforcel 已提交
2356
9.  Define the loss function and the optimization algorithms. Use the Adam optimizer and the cross-entropy loss to do this. Train the network for`20`epochs:
W
wizardforcel 已提交
2357 2358 2359 2360 2361 2362 2363

    loss_function = nn.CrossEntropyLoss()

    优化程序= optim.Adam(model.parameters(),lr = 0.001)

    时代= 20

W
wizardforcel 已提交
2364
    如果您的机器有可用的 GPU,请尝试运行`500`时期的训练过程:
W
wizardforcel 已提交
2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411

    时代= 500

10.  In each epoch, the data must be divided into batches with a sequence length of 50\. This means that each epoch will have 100 batches, each with a sequence of 50:

    损失= []

    对于范围(1,历元+1)中的 e:

    状态= model.init_states(n_seq)

    batch_loss = []

    对于范围为(0,x .shape [1],seq_length)的 b:

    x_batch = x [:,b:b + seq_length]

    如果 b == x.shape [1]-seq_length:

    y_batch = x [:,b + 1:b + seq_length]

    y_batch = np.hstack((y_batch,indexer [“。”] \

    * np.ones((y_batch.shape [0],1))))

    其他:

    y_batch = x [:,b + 1:b + seq_length + 1]

    x_onehot =火炬张量(index2onehot(x_batch))

    y =火炬。张量(y_batch).view(n_seq * seq_length)

    pred,状态=模型(x_onehot,状态)

    损失= loss_function(pred,y.long())

    Optimizer.zero_grad()

    loss.backward(retain_graph = True)

    Optimizer.step()

    batch_loss.append(loss.item())

    loss.append(np.mean(batch_loss))

W
wizardforcel 已提交
2412
    如果 e% 2 == 0:
W
wizardforcel 已提交
2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485

    print(“ epoch:”,e,“ ...损失函数:”,损失[-1])

    输出应如下所示:

    时代:2 ...损失函数:3.1667490992052802

    时代:4 ...损失函数:3.1473221943296235

    时期:6 ...损失函数:2.897721455014985

    时代:8 ...损失函数:2.567064647016854

    时代:10 ...损失函数:2.4197753791151375

    时期:12 ...损失函数:2.314083896834275

    时代:14 ...损失函数:2.2241266349266313

    时期:16 ...损失函数:2.1459227183769487

    时代:18 ...损失函数:2.0731402758894295

    时代:20 ...损失函数:2.0148646708192497

    如果您的计算机具有可用的 GPU,则用于训练网络的等效代码段如下所示:

    损失= []

    对于范围(1,历元+1)中的 e:

    状态= model.init_states(n_seq)

    batch_loss = []

    对于范围为(0,x.shape [1],seq_length)的 b:

    x_batch = x [:,b:b + seq_length]

    如果 b == x.shape [1]-seq_length:

    y_batch = x [:,b + 1:b + seq_length]

    y_batch = np.hstack((y_batch,indexer [“。”] \

    * np.ones((y_batch.shape [0],1))))

    其他:

    y_batch = x [:,b + 1:b + seq_length + 1]

    x_onehot =火炬张量(index2onehot(x_batch))\

    .to("cuda")

    y =火炬。张量(y_batch).view(n_seq * \

    seq_length).to(“ cuda”)

    pred,状态=模型(x_onehot,状态)

    损失= loss_function(pred,y.long())

    Optimizer.zero_grad()

    loss.backward(retain_graph = True)

    Optimizer.step()

    batch_loss.append(loss.item())

    loss.append(np.mean(batch_loss))

W
wizardforcel 已提交
2486
    如果 e% 50 == 0:
W
wizardforcel 已提交
2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545

    print(“ epoch:”,e,“ ...损失函数:”,\

    损失[-1])

    将训练过程运行 500 个纪元的结果如下:

    时代:50 ...损失函数:1.5207843986050835

    时代:100 ...损失函数:1.006190665836992

    时代:150 ...损失函数:0.5197970939093622

    时期:200 ...损失函数:0.24446514968214364

    时期:250 ...损失函数:0.0640328845073437

    时期:300 ...损失函数:0.007852113484565553

    时期:350 ...损失函数:0.003644719101681278

    时代:400 ...损失函数:0.006955199634078248

    时代:450 ...损失函数:0.0030021724242973945

    时代:500 ...损失函数:0.0034294885518992768

    可以看出,通过将训练过程运行更多的时间段,损失函数将达到较低的值。

11.  Plot the progress of the loss over time:

    x_range =范围(len(损失))

    plt.plot(x_range,损失)

    plt.xlabel(“时代”)

    plt.ylabel(“损失函数”)

    plt.show()

    该图表应如下所示:

    ![Figure 6.30: Chart displaying the progress of the loss function ](img/B15778_06_30.jpg)

    图 6.30:显示损失函数进度的图表

    如我们所见,在 20 个历元之后,损失函数仍然可以减少,这就是为什么强烈建议训练更多历元以便从模型中获得良好结果的原因。

12.  Feed the following sentence **starter** into the trained model for it to complete the sentence: **"So she was considering in her own mind "**:

    starter =“所以她在 中考虑自己的想法”

    状态=无

    如果您的计算机具有可用的 GPU,则将模型分配回 CPU 以执行预测:

    型号= model.to(“ cpu”)

W
wizardforcel 已提交
2546
    首先,`for`循环的将种子输入模型,以便可以生成内存。 接下来,执行预测,如以下代码片段所示:
W
wizardforcel 已提交
2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587

    对于启动器中的 ch:

    x = np.array([[indexer [ch]]])

    x = index2onehot(x)

    x =火炬张量(x)

    pred,状态=模型(x,状态)

    计数器= 0

    而 starter [-1]!=“ 且计数器<100:

    计数器+ = 1

    x = np.array([[indexer [starter [-1]]]])

    x = index2onehot(x)

    x =火炬张量(x)

    pred,状态=模型(x,状态)

    pred = F.softmax(pred,dim = 1)

    p,上层=上一层(10)

    p = p.detach()。numpy()[0]

    top = top.numpy()[0]

    索引= np.random.choice(top,p = p / p.sum())

    入门级+ =字符[索引]

    打印(入门)

    注意

W
wizardforcel 已提交
2588
    要访问此特定部分的源代码,请参考[这里](https://packt.live/2Bs6dRZ)。
W
wizardforcel 已提交
2589 2590 2591

    本部分当前没有在线交互示例,需要在本地运行。

W
wizardforcel 已提交
2592
    要访问此源代码的 GPU 版本,请参考[这里](https://packt.live/3g9X6UI)。 此版本的源代码无法作为在线交互示例使用,需要通过 GPU 设置在本地运行。
W
wizardforcel 已提交
2593 2594 2595 2596 2597

## 活动 6.03:执行情感分析的 NLP

### 解决方案

W
wizardforcel 已提交
2598
1.  导入所需的库。
W
wizardforcel 已提交
2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615

    将熊猫作为 pd 导入

    将 numpy 导入为 np

    导入 matplotlib.pyplot 作为 plt

    从字符串导入标点

    从 sklearn.metrics 导入 precision_score

    进口火炬

    从火炬进口 nn,乐观

    导入功能为 F 的 torch.nn。

W
wizardforcel 已提交
2616
2.  Load the dataset containing a set of 1,000 product reviews from Amazon, which is paired with a label of`0`(for negative reviews) or`1`(for positive reviews). Separate the data into two variables – one containing the reviews and the other containing the labels:
W
wizardforcel 已提交
2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689

    数据= pd.read_csv(“ amazon_cells_labelled.txt”,sep =“ \ t”,\

    标头=无)

    评论= data.iloc [:,0] .str.lower()

    情绪= data.iloc [:,1] .values

3.  Remove the punctuation from the reviews:

    对于我的标点符号:

    评论= reviews.str.replace(i,“”)

4.  Create a variable containing the vocabulary of the entire set of reviews. Additionally, create a dictionary that maps each word to an integer, where the words will be the keys and the integers will be the values:

    words =''.join(评论)

    单词= words.split()

    词汇=设置(单词)

    indexer = {word :(索引,单词)的索引\

    枚举(词汇)}

5.  Encode the reviews data by replacing each word in a review with its paired integer:

    indexed_reviews = []

    在评论中进行评论:

    indexed_reviews.append([indexer [word] \

    for review.split()中的单词)

6.  Create a class containing the architecture of the network. Make sure that you include an embedding layer:

    LSTM(nn.Module)类:

    def __init __(self,vocab_size,embed_dim,\

    hidden_​​size,n_layers):

    super().__ init __()

    self.hidden_​​size = hidden_​​size

    self.embedding = nn.Embedding(vocab_size,embed_dim)

    self.lstm = nn.LSTM(embed_dim,hidden_​​size,\

    n_layers,batch_first = True)

    self.output = nn.Linear(hidden_​​size,1)

    def forward(self,x):

    出= self.embedding(x)

    出,_ = self.lstm(出)

    out = out.contiguous()。view(-1,self.hidden_​​size)

    out = self.output(输出)

    出=出[-1,0]

    out =火炬.sigmoid(out).unsqueeze(0)

    返回

W
wizardforcel 已提交
2690
    该类包含用于定义网络架构的`__init__`方法和用于确定数据流经不同层的方式的`forward`方法。
W
wizardforcel 已提交
2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765

7.  Instantiate the model using 64 embedding dimensions and 128 neurons for three LSTM layers:

    模型= LSTM(仅(词汇),64、128、3)

    模型

    运行前面的代码将显示以下输出:

    LSTM(

    (嵌入):嵌入(1905,64)

    (lstm):LSTM(64、128,num_layers = 3,batch_first = True)

    (输出):线性(in_features = 128,out_features = 1,bias = True)

    )

8.  Define the loss function, an optimization algorithm, and the number of epochs to train for. For example, you can use the binary cross-entropy loss as the loss function, the Adam optimizer, and train for 10 epochs:

    loss_function = nn.BCELoss()

    优化程序= optim.Adam(model.parameters(),lr = 0.001)

    时代= 10

9.  Create a **for** loop that goes through the different epochs and through every single review individually. For each review, perform a prediction, calculate the loss function, and update the parameters of the network. Additionally, calculate the accuracy of the network on that training data:

    损失= []

    acc = []

    对于范围(1,历元+1)中的 e:

    single_loss = []

    preds = []

    目标= []

    对于我来说,r 在枚举(indexed_reviews)中:

    如果 len(r)<= 1:

    继续

    x =火炬.Tensor([r])。long()

    y = Torch.Tensor([sentiment [i]])

    之前=模型(x)

    损失= loss_function(pred,y)

    Optimizer.zero_grad()

    loss.backward()

    Optimizer.step()

    final_pred = np.round(pred.detach()。numpy())

    preds.append(final_pred)

    target.append(y)

    single_loss.append(loss.item())

    loss.append(np.mean(single_loss))

    精度=精度得分(目标,优势)

    追加(精度)

W
wizardforcel 已提交
2766
    如果 e% 1 == 0:
W
wizardforcel 已提交
2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791

    print(“ Epoch:”,e,“ ...损失函数:”,损失[-1],\

    “ ...精度:”,acc [-1])

    与以前的活动一样,训练过程包括进行预测,将其与基本事实进行比较以计算损失函数,并执行向后传递以最小化损失函数。

10.  Plot the progress of the loss and accuracy over time. The following code is used to plot the loss function:

    x_range =范围(len(损失))

    plt.plot(x_range,损失)

    plt.xlabel(“时代”)

    plt.ylabel(“损失函数”)

    plt.show()

    该图应如下所示:

![Figure 6.31: Plot displaying the progress of the loss function  ](img/B15778_06_31.jpg)

图 6.31:显示损失函数进度的图

W
wizardforcel 已提交
2792
以下代码用于绘制准确率得分:
W
wizardforcel 已提交
2793 2794 2795 2796 2797 2798 2799

x_range =范围(len(acc))

plt.plot(x_range,acc)

plt.xlabel(“时代”)

W
wizardforcel 已提交
2800
plt.ylabel(“准确率得分”)
W
wizardforcel 已提交
2801 2802 2803 2804 2805 2806 2807

plt.show()

该图应如下所示:

![Figure 6.32: Plot displaying the progress of the accuracy score ](img/B15778_06_32.jpg)

W
wizardforcel 已提交
2808
图 6.32:显示准确率得分进度的图
W
wizardforcel 已提交
2809 2810 2811

注意

W
wizardforcel 已提交
2812
要访问此特定部分的源代码,请参考[这里](https://packt.live/2VyX0ON)
W
wizardforcel 已提交
2813 2814

本部分当前没有在线交互示例,需要在本地运行。