李沐 代码

博文 http://bestzhangjin.com/2017/10/13/deeplearn/

目录

 

深度学习之Mxnet--李沐视频

1.1.前言

1.2.使用NDArray来处理数据

1.3.使用autograd自动求导

1.4.从0开始线性回归

1.5.使用Gluon实现线性回归

1.6.从0开始多类逻辑回归

1.7.Gluon版多类逻辑回归

2.1.从0开始多层感知机

2.2.使用Gluon多层感知机

2.3.从0开始正则化

2.3.使用Gluon正则化

2.4.使用GPU来计算

2.5.从0开始卷积神经网络

2.6.使用gluon卷积神经网络

3.1.创建神经网络

3.2.初始化模型参数

3.3.序列化读写模型

3.4.设计自定义层

3.5.dropout

3.6.使用Gluon丢弃法(Dropout)

3.7.深度卷积神经网络和AlexNet

3.8.VGGNet

4.1. 从0开始批量归一化BatchNorm

4.2.gluon版batchnorm

4.3.网络中的网络NIN

4.4.GoogleNet

4.5.Resnet

4.6.DenseNet

4.7.图片增强

8.1 使用Gluon实现SSD


深度学习之Mxnet--李沐视频

发表于 2017-10-13   |   分类于 深度学习   |  

1.1.前言

资料详见动手学深度学习

1.2.使用NDArray来处理数据

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
# coding=utf-8

from mxnet import ndarray as nd
import numpy as np
##具体看NDArray API

nd.zeros((3, 4))  #3行和4列的2D数组 全0
x=nd.ones((3,4)) #全1
#或者从python的数组直接构造
nd.array([[1,2],[2,3]]) #[[ 1.  2.] [ 2.  3.]]
## 创建随机数 - 深度学习常用
y = nd.random_normal(0, 1, shape=(3, 4)) #均值0方差1的正态分布3x4矩阵
print y.shape # (3L, 4L)
print y.size # 12

##数学操作  nd.dot(x,y)为矩阵乘法 区别于*对应元素相乘
x+y
x*y
print nd.exp(y) ##指数
print nd.dot(x,y.T) #x与y的转置进行矩阵乘法

##Numpy与NDArray转换
x = np.ones((2,3))
y = nd.array(x)  # numpy -> mxnet
z = y.asnumpy()  # mxnet -> numpy
print([z, y])

1.3.使用autograd自动求导

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
# coding=utf-8

from mxnet import ndarray as nd
import mxnet.autograd as ag ##自动求导
import numpy as np

x = nd.array([[1, 2], [3, 4]])
#对需要求导的变量需要通过NDArray的方法`attach_grad()`来要求系统申请对应的空间
x.attach_grad()

#默认条件下,MXNet不会自动记录和构建用于求导的计算图,
# 我们需要使用autograd里的`record()`函数来显式的要求MXNet记录我们需要求导的程序。
with ag.record():
    y = x * 2
    z = y * x  ##z=2乘以x的平方 [[  2.   8.] [ 18.  32.]]

#接下来我们可以通过z.backward()来进行求导。
# 如果z不是一个标量,那么z.backward()等价于nd.sum(z).backward()
z.backward() ## None
print x.grad  # z针对x求导的结果 [[  4.   8.] [ 12.  16.]]
## x.grad == 4*x
print x.grad == 4*x  ## [[ 1.  1.] [ 1.  1.]]

## 对控制流求导
def f(a):
    b = a * 2
    ## nd.norm(b)-b中所有数据的平方之和取根号 asscalar()--转换成标量
    while nd.norm(b).asscalar() < 1000:
        b = b * 2
    if nd.sum(b).asscalar() > 0:
        c = b
    else:
        c = 100 * b
    return c

a = nd.random_normal(shape=3)
a.attach_grad()
with ag.record():
    c = f(a)
c.backward()
print a.grad # [ 512.  512.  512.]
print a.grad==c/a # [ 1.  1.  1.]

1.4.从0开始线性回归

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
# coding=utf-8

from mxnet import ndarray as nd
from mxnet import autograd
import random

num_inputs = 2
num_examples = 1000

true_w = [2, -3.4]
true_b = 4.2

X = nd.random_normal(shape=(num_examples, num_inputs))
y = true_w[0] * X[:, 0] + true_w[1] * X[:, 1] + true_b
y += .01 * nd.random_normal(shape=y.shape) ##加噪声

# 注意到`X`的每一行是一个长度为2的向量,而`y`的每一行是一个长度为1的向量(标量)。

print(X[0], y[0]) # [[ 2.21220636  1.16307867],[ 4.6620779]]

# 当我们开始训练神经网络的时候,我们需要不断读取数据块。
# 这里我们定义一个函数它每次返回batch_size个随机的样本和对应的目标。
# 我们通过python的yield来构造一个迭代器。
batch_size = 10
def data_iter():
    # 产生一个随机索引
    idx = list(range(num_examples))
    random.shuffle(idx) ##索引打乱顺序
    for i in range(0, num_examples, batch_size):
        j = nd.array(idx[i:min(i+batch_size,num_examples)]) #随机的batch个索引
        yield nd.take(X, j), nd.take(y, j) #根据索引拿到数据

for data, label in data_iter():
    print(data, label)
    break

n=0
for data, label in data_iter():
    n=n+1
print n ## 100 每次拿10组数据 拿100次拿完


#下面我们随机初始化模型参数
w = nd.random_normal(shape=(num_inputs, 1))
b = nd.zeros((1,))
params = [w, b]
print params # [[ 0.72455114] [ 0.13263007]], [ 0.]]

# 之后训练时我们需要对这些参数求导来更新它们的值,所以我们需要创建它们的梯度
for param in params:
    param.attach_grad()

## 定义模型
# 线性模型就是将输入和模型做乘法再加上偏移:
def net(X):
    return nd.dot(X, w) + b

## 损失函数
#我们使用常见的平方误差来衡量预测目标和真实目标之间的差距。
def square_loss(yhat, y):
    # 注意这里我们把y变形成yhat的形状来避免自动广播
    return (yhat - y.reshape(yhat.shape)) ** 2

#虽然线性回归有显试解,但绝大部分模型并没有。
# 所以我们这里通过随机梯度下降来求解。每一步,
# 我们将模型参数沿着梯度的反方向走特定距离,这个距离一般叫学习率。
def SGD(params, lr):
    for param in params:
        param[:] = param - lr * param.grad

## 训练
# 现在我们可以开始训练了。训练通常需要迭代数据数次,
# 一次迭代里,我们每次随机读取固定数个数据点,计算梯度并更新模型参数。
epochs = 10
learning_rate = .001
for e in range(epochs):
    total_loss = 0
    for data, label in data_iter():
        with autograd.record():
            output = net(data)
            loss = square_loss(output, label)
        loss.backward()
        SGD(params, learning_rate)
        total_loss += nd.sum(loss).asscalar()
    print("Epoch %d, average loss: %f" % (e, total_loss/num_examples))

print true_w,w  #[2, -3.4]  [[ 1.99984801] [-3.40017033]]
print true_b,b  #4.2  [ 4.19996023]

1.5.使用Gluon实现线性回归

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
# coding=utf-8

from mxnet import ndarray as nd
from mxnet import autograd
from mxnet import gluon

## 创建数据集
num_inputs = 2
num_examples = 1000
true_w = [2, -3.4]
true_b = 4.2

X = nd.random_normal(shape=(num_examples, num_inputs))
y = true_w[0] * X[:, 0] + true_w[1] * X[:, 1] + true_b
y += .01 * nd.random_normal(shape=y.shape)

## 数据读取
batch_size = 10
dataset = gluon.data.ArrayDataset(X, y)
data_iter = gluon.data.DataLoader(dataset, batch_size, shuffle=True)

for data, label in data_iter:
    print(data, label)
    break

## 定义模型
# 当我们手写模型的时候,我们需要先声明模型参数,然后再使用它们来构建模型。
# 但gluon提供大量提前定制好的层,使得我们只需要主要关注使用哪些层来构建模型。
# 例如线性模型就是使用对应的Dense层。
#虽然我们之后会介绍如何构造任意结构的神经网络,
# 构建模型最简单的办法是利用Sequential来所有层串起来。
# 首先我们定义一个空的模型:
net = gluon.nn.Sequential()

#然后我们加入一个Dense层,它唯一必须要定义的参数就是输出节点的个数,在线性模型里面是1.
#这里我们并没有定义说这个层的输入节点是多少,这个在之后真正给数据的时候系统会自动赋值。
net.add(gluon.nn.Dense(1))
print net  #Sequential((0): Dense(1, linear))

# 在使用前net我们必须要初始化模型权重,这里我们使用默认随机初始化方法
# (之后我们会介绍更多的初始化方法)。
net.initialize()

## 损失函数
# gluon提供了平方误差函数:
square_loss = gluon.loss.L2Loss()

## 优化
#同样我们无需手动实现随机梯度下降,我们可以用创建一个Trainer的实例,
# 并且将模型参数传递给它就行。
trainer = gluon.Trainer(
    net.collect_params(), 'sgd', {'learning_rate': 0.1})

## 训练
# 这里的训练跟前面没有太多区别,唯一的就是我们不再是调用SGD,
# 而是trainer.step来更新模型。
epochs = 5
batch_size = 10
for e in range(epochs):
    total_loss = 0
    for data, label in data_iter:
        with autograd.record():
            output = net(data)
            loss = square_loss(output, label)
        loss.backward()
        trainer.step(batch_size) ##往前走一步
        total_loss += nd.sum(loss).asscalar()
    print("Epoch %d, average loss: %f" % (e, total_loss/num_examples))

# 比较学到的和真实模型。我们先从`net`拿到需要的层,然后访问其权重和位移。
dense = net[0]
print true_w, dense.weight.data() ##[2, -3.4]  [[ 1.99912584 -3.39986587]]
print true_b, dense.bias.data() ##4.2  [ 4.19950867]

1.6.从0开始多类逻辑回归

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
# coding=utf-8

from mxnet import gluon
from mxnet import ndarray as nd

#这里我们用MNIST分类数字
# 我们通过gluon的data.vision模块自动下载这个数据。
def transform(data, label):
    return data.astype('float32')/255, label.astype('float32')
mnist_train = gluon.data.vision.MNIST(train=True, transform=transform)
mnist_test = gluon.data.vision.MNIST(train=False, transform=transform)

# 打印一个样本的形状和它的标号
data, label = mnist_train[0]
print ('example shape: ', data.shape, 'label:', label) ##('example shape: ', (28L, 28L, 1L), 'label:', 5.0)

## 数据读取
#虽然我们可以像前面那样通过yield来定义获取批量数据函数,
# 这里我们直接使用gluon.data的DataLoader函数,它每次yield一个批量。
# 注意到这里我们要求每次从训练数据里读取一个由随机样本组成的批量,
# 但测试数据则不需要这个要求。
batch_size = 256
train_data = gluon.data.DataLoader(mnist_train, batch_size, shuffle=True)
test_data = gluon.data.DataLoader(mnist_test, batch_size, shuffle=False)


## 初始化模型参数
# 跟线性模型一样,每个样本会表示成一个向量。我们这里数据是 28 * 28 大小的图片,
# 所以输入向量的长度是 28 * 28 = 784。
# 因为我们要做多类分类,我们需要对每一个类预测这个样本属于此类的概率。
# 因为这个数据集有10个类型,所以输出应该是长为10的向量。
# 这样,我们需要的权重将是一个 784 * 10 的矩阵:
num_inputs = 784
num_outputs = 10
W = nd.random_normal(shape=(num_inputs, num_outputs))
b = nd.random_normal(shape=num_outputs)
params = [W, b]

#同之前一样,我们要对模型参数附上梯度:
for param in params:
    param.attach_grad()

## 定义模型
# 在线性回归教程里,我们只需要输出一个标量yhat使得尽可能的靠近目标值。
# 但在这里的分类里,我们需要属于每个类别的概率。
# 这些概率需要值为正,而且加起来等于1.
# 而如果简单的使用 Y=WX,我们不能保证这一点。
# 一个通常的做法是通过softmax函数来将任意的输入归一化成合法的概率值。
from mxnet import nd
def softmax(X):
    exp = nd.exp(X)  ##全部变为正的
    # 假设exp是矩阵,这里对行进行求和,并要求保留axis 1,
    # 就是返回 (nrows, 1) 形状的矩阵
    partition = exp.sum(axis=1, keepdims=True)
    return exp / partition  ##每个行除以它的行的和

#可以看到,对于随机输入,我们将每个元素变成了非负数,而且每一行加起来为1。
X = nd.random_normal(shape=(2,5))
print X
# [[ 0.79687113  0.85240501  0.61860603  0.47654876  0.74863517]
# [ 0.55032933 -0.22566749 -2.11320662 -0.95748073  0.32560727]]
X_prob = softmax(X)
print(X_prob)
# [[ 0.21869159  0.23117994  0.18298376  0.1587515   0.20839317]
# [ 0.39214477  0.1804826   0.02733301  0.08681861  0.31322101]]
print(X_prob.sum(axis=1)) # [ 0.99999994  1.        ] ([1,1])

#现在我们可以定义模型了:
def net(X):
    return softmax(nd.dot(X.reshape((-1,num_inputs)), W) + b)

## 交叉熵损失函数
# 我们需要定义一个针对预测为概率值的损失函数。其中最常见的是交叉熵损失函数,
# 它将两个概率分布的负交叉熵作为目标值,最小化这个值等价于最大化这两个概率的相似度。
# 具体来说,我们先将真实标号表示成一个概率分布,例如如果y=1,
# 那么其对应的分布就是一个除了第二个元素为1其他全为0的长为10的向量,
# 也就是 yvec=[0, 1, 0, 0, 0, 0, 0, 0, 0, 0]。
# 那么交叉熵就是yvec[0]*log(yhat[0])+...+yvec[n]*log(yhat[n])。
# 注意到yvec里面只有一个1,那么前面等价于log(yhat[y])。
# 所以我们可以定义这个损失函数了
def cross_entropy(yhat, y):
    return - nd.pick(nd.log(yhat), y)

#给定一个概率输出,我们将预测概率最高的那个类作为预测的类,
# 然后通过比较真实标号我们可以计算精度:
def accuracy(output, label):
    return nd.mean(output.argmax(axis=1)==label).asscalar()


#我们可以评估一个模型在这个数据上的精度。
def evaluate_accuracy(data_iterator, net):
    acc = 0.
    for data, label in data_iterator:
        output = net(data)
        acc += accuracy(output, label)
    return acc / len(data_iterator)

#因为我们随机初始化了模型,所以这个模型的精度应该大概是1/num_outputs = 0.1.
print evaluate_accuracy(test_data, net) #0.09814453125

def SGD(params, lr):
    for param in params:
        param[:] = param - lr * param.grad

## 训练
import sys
sys.path.append('..')
from mxnet import autograd

learning_rate = .1
for epoch in range(5):
    train_loss = 0.
    train_acc = 0.
    for data, label in train_data:
        with autograd.record():
            output = net(data)
            loss = cross_entropy(output, label)
        loss.backward()
        # 将梯度做平均,这样学习率会对batch size不那么敏感
        SGD(params, learning_rate/batch_size)

        train_loss += nd.mean(loss).asscalar()
        train_acc += accuracy(output, label)

    test_acc = evaluate_accuracy(test_data, net)
    print("Epoch %d. Loss: %f, Train acc %f, Test acc %f" % (
        epoch, train_loss/len(train_data), train_acc/len(train_data), test_acc))

## 预测
#训练完成后,现在我们可以演示对输入图片的标号的预测

data, label = mnist_test[0:9]
print('true labels')
print(label)

predicted_labels = net(data).argmax(axis=1)
print('predicted labels')
print(predicted_labels.asnumpy())

尝试增大学习率,你会发现结果马上回变成很糟糕,精度基本徘徊在随机的0.1左右。这是为什么呢?提示:

  • 打印下output看看是不是有有什么异常
  • 前面线性回归还好好的,这里我们在net()里加了什么呢?
  • 如果给exp输入个很大的数会怎么样?
  • 即使解决exp的问题,求出来的导数是不是还是不稳定?

请仔细想想再去对比下小伙伴之一@pluskid早年写的一篇blog解释这个问题,看看你想的是不是不一样。

1.7.Gluon版多类逻辑回归

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
# coding=utf-8

from mxnet import gluon
from mxnet import ndarray as nd
from mxnet import autograd
from mxnet import image

batch_size = 256
#这里我们用MNIST分类数字
def load_data_fashion_mnist(batch_size, resize=None):
    """download the fashion mnist dataest and then load into memory"""
    def transform_mnist(data, label):
        if resize:
            # resize to resize x resize
            data = image.imresize(data, resize, resize)
        # change data from height x weight x channel to channel x height x weight
        return nd.transpose(data.astype('float32'), (2,0,1))/255, label.astype('float32')
    mnist_train = gluon.data.vision.MNIST(train=True, transform=transform_mnist)
    mnist_test = gluon.data.vision.MNIST(train=False, transform=transform_mnist)
    train_data = gluon.data.DataLoader(mnist_train, batch_size, shuffle=True)
    test_data = gluon.data.DataLoader(mnist_test, batch_size, shuffle=False)
    return (train_data, test_data)

def transform(data, label):
    return data.astype('float32')/255, label.astype('float32')
mnist_train,mnist_test  = load_data_fashion_mnist(batch_size)

# 我们先使用Flatten层将输入数据转成batch_size的矩阵?
# 然后输入到10个输出节点的全连接层。
# 照例我们不需要制定每层输入的大小,gluon会做自动推导。
net = gluon.nn.Sequential()
with net.name_scope():
    net.add(gluon.nn.Flatten())
    net.add(gluon.nn.Dense(10))
net.initialize()

# 然后通过比较真实标号我们可以计算精度:
def accuracy(output, label):
    return nd.mean(output.argmax(axis=1)==label).asscalar()

#我们可以评估一个模型在这个数据上的精度。
def evaluate_accuracy(data_iterator, net):
    acc = 0.
    for data, label in data_iterator:
        output = net(data)
        acc += accuracy(output, label)
    return acc / len(data_iterator)

## Softmax和交叉熵损失函数
#如果你做了上一章的练习,那么你可能意识到了分开定义Softmax和交叉熵会有数值不稳定性
softmax_cross_entropy = gluon.loss.SoftmaxCrossEntropyLoss()

## 优化
trainer = gluon.Trainer(net.collect_params(), 'sgd', {'learning_rate': 0.1})

## 训练
for epoch in range(5):
    train_loss = 0.
    train_acc = 0.
    for data, label in mnist_train:
        with autograd.record():
            output = net(data)
            loss = softmax_cross_entropy(output, label)
        loss.backward()
        trainer.step(batch_size)

        train_loss += nd.mean(loss).asscalar()
        train_acc += accuracy(output, label)
    test_acc = evaluate_accuracy(mnist_test, net)
    print("Epoch %d. Loss: %f, Train acc %f, Test acc %f" % (
        epoch, train_loss/len(mnist_train), train_acc/len(mnist_train), test_acc))

2.1.从0开始多层感知机

前面我们介绍了包括线性回归和多类逻辑回归的数个模型,它们的一个共同点是全是只含有一个输入层,一个输出层。这一节我们将介绍多层神经网络,就是包含至少一个隐含层的网络。

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
# coding=utf-8

from mxnet import gluon
from mxnet import ndarray as nd
from mxnet import autograd
from mxnet import image


#这里我们用MNIST分类数字
def load_data_fashion_mnist(batch_size, resize=None):
    """download the fashion mnist dataest and then load into memory"""
    def transform_mnist(data, label):
        if resize:
            # resize to resize x resize
            data = image.imresize(data, resize, resize)
        # change data from height x weight x channel to channel x height x weight
        return nd.transpose(data.astype('float32'), (2,0,1))/255, label.astype('float32')
    mnist_train = gluon.data.vision.MNIST(train=True, transform=transform_mnist)
    mnist_test = gluon.data.vision.MNIST(train=False, transform=transform_mnist)
    train_data = gluon.data.DataLoader(mnist_train, batch_size, shuffle=True)
    test_data = gluon.data.DataLoader(mnist_test, batch_size, shuffle=False)
    return (train_data, test_data)


batch_size = 256
train_data, test_data = load_data_fashion_mnist(batch_size)

# 这里我们定义一个只有一个隐含层的模型,这个隐含层输出256个节点。
num_inputs = 28*28
num_outputs = 10
num_hidden = 256
weight_scale = .01

##定义两层
W1 = nd.random_normal(shape=(num_inputs, num_hidden), scale=weight_scale)
b1 = nd.zeros(num_hidden)
W2 = nd.random_normal(shape=(num_hidden, num_outputs), scale=weight_scale)
b2 = nd.zeros(num_outputs)

params = [W1, b1, W2, b2]
for param in params:
    param.attach_grad()

## 激活函数
#如果我们就用线性操作符来构造多层神经网络,那么整个模型仍然只是一个线性函数。
# 为了让我们的模型可以拟合非线性函数,我们需要在层之间插入非线性的激活函数。这里我们使用ReLU
def relu(X):
    return nd.maximum(X, 0)

## 定义模型
#我们的模型就是将层(全连接)和激活函数(Relu)串起来:
def net(X):
    X = X.reshape((-1, num_inputs))
    h = relu(nd.dot(X, W1) + b1)
    output = nd.dot(h, W2) + b2
    return output

## Softmax和交叉熵损失函数
#在多类Logistic回归里我们提到分开实现Softmax和交叉熵损失函数可能导致数值不稳定。
# 这里我们直接使用Gluon提供的函数
softmax_cross_entropy = gluon.loss.SoftmaxCrossEntropyLoss()

# 然后通过比较真实标号我们可以计算精度:
def accuracy(output, label):
    return nd.mean(output.argmax(axis=1)==label).asscalar()

#我们可以评估一个模型在这个数据上的精度。
def evaluate_accuracy(data_iterator, net):
    acc = 0.
    for data, label in data_iterator:
        output = net(data)
        acc += accuracy(output, label)
    return acc / len(data_iterator)

def SGD(params, lr):
    for param in params:
        param[:] = param - lr * param.grad

## 训练
learning_rate = .5
for epoch in range(20):
    train_loss = 0.
    train_acc = 0.
    for data, label in train_data:
        with autograd.record():
            output = net(data)
            loss = softmax_cross_entropy(output, label)
        loss.backward()
        SGD(params, learning_rate/batch_size)

        train_loss += nd.mean(loss).asscalar()
        train_acc += accuracy(output, label)

    test_acc = evaluate_accuracy(test_data, net)
    print("Epoch %d. Loss: %f, Train acc %f, Test acc %f" % (
        epoch, train_loss/len(train_data),
        train_acc/len(train_data), test_acc))

 

可以看到,加入一个隐含层后我们将精度提升了不少。

练习

  • 我们使用了 weight_scale 来控制权重的初始化值大小,增大或者变小这个值会怎么样?
  • 尝试改变 num_hiddens 来控制模型的复杂度
  • 尝试加入一个新的隐含层
    注意:针对不同的数据,模型可能并非越复杂越好
    测试结果:加大num_hiddens得到了更好的结果,添加隐藏层后更加容易过拟合

2.2.使用Gluon多层感知机

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
# coding=utf-8

from mxnet import gluon
from mxnet import ndarray as nd
from mxnet import autograd
from mxnet import image

#这里我们用MNIST分类数字
def load_data_fashion_mnist(batch_size, resize=None):
    """download the fashion mnist dataest and then load into memory"""
    def transform_mnist(data, label):
        if resize:
            # resize to resize x resize
            data = image.imresize(data, resize, resize)
        # change data from height x weight x channel to channel x height x weight
        return nd.transpose(data.astype('float32'), (2,0,1))/255, label.astype('float32')
    mnist_train = gluon.data.vision.MNIST(train=True, transform=transform_mnist)
    mnist_test = gluon.data.vision.MNIST(train=False, transform=transform_mnist)
    train_data = gluon.data.DataLoader(mnist_train, batch_size, shuffle=True)
    test_data = gluon.data.DataLoader(mnist_test, batch_size, shuffle=False)
    return (train_data, test_data)

def accuracy(output, label):
    return nd.mean(output.argmax(axis=1)==label).asscalar()
def evaluate_accuracy(data_iterator, net):
    acc = 0.
    for data, label in data_iterator:
        output = net(data)
        acc += accuracy(output, label)
    return acc / len(data_iterator)

## 定义模型
#唯一的区别在这里,我们加了一行进来。
net = gluon.nn.Sequential()
with net.name_scope():
    net.add(gluon.nn.Flatten())
    net.add(gluon.nn.Dense(256, activation="relu"))
    net.add(gluon.nn.Dense(10))
net.initialize()

## 读取数据并训练
batch_size = 256
train_data, test_data = load_data_fashion_mnist(batch_size)

softmax_cross_entropy = gluon.loss.SoftmaxCrossEntropyLoss()
trainer = gluon.Trainer(net.collect_params(), 'sgd', {'learning_rate': 0.5})

for epoch in range(5):
    train_loss = 0.
    train_acc = 0.
    for data, label in train_data:
        with autograd.record():
            output = net(data)
            loss = softmax_cross_entropy(output, label)
        loss.backward()
        trainer.step(batch_size)

        train_loss += nd.mean(loss).asscalar()
        train_acc += accuracy(output, label)

    test_acc = evaluate_accuracy(test_data, net)
    print("Epoch %d. Loss: %f, Train acc %f, Test acc %f" % (
        epoch, train_loss/len(train_data), train_acc/len(train_data), test_acc))

通过Gluon我们可以更方便地构造多层神经网络。
练习

  • 尝试多加入几个隐含层,对比从0开始的实现。
  • 尝试使用一个另外的激活函数,可以使用help(nd.Activation)或者线上文档查看提供的选项。

2.3.从0开始正则化

本章从0开始介绍如何的正则化来应对过拟合问题。
L2范数正则化
这里我们引入$L_2$范数正则化。不同于在训练时仅仅最小化损失函数(Loss),我们在训练时其实在最小化
img1
直观上,L2范数正则化试图惩罚较大绝对值的参数值。训练模型时,如果λ=0则没有正则化,需要注意的是,测试模型时,λ必须为0。

高维线性回归
我们使用高维线性回归为例来引入一个过拟合问题。
img2
需要注意的是,我们用以上相同的数据生成函数来生成训练数据集和测试数据集。为了观察过拟合,我们特意把训练数据样本数设低,例如n=20,同时把维度升高,例如p=200.

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
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值