深度学习-->线性回归模型

# 线性回归

# 创建数据集
from mxnet import ndarray as nd
from mxnet import autograd as ad

num_input = 2
num_examples = 1000

true_w = [2, -3.4]
true_b = 4.2

x = nd.random_normal(shape=(num_examples, num_input))
y = true_w[0] * x[:, 0] + true_w[1] * x[:, 1] + true_b
y += .01 * nd.random_normal(shape=y.shape)
print(x[0:10], y[0:10])
# 数据读取
import random

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)])
        yield nd.take(x, j), nd.take(y, j)  # 返回这两个数,对应下面的data,label,每次在在十个里面拿一个样例和一个结果


for data, label in data_iter():
    print(data, label)
# 查看要取多少次
n = 0
for data, label in data_iter():
    n = n + 1
print(n)  # 要取100次,因为有1000个样例,每次取10个

# 初始化模型参数
w = nd.random_normal(shape=(num_input, 1))
b = nd.zeros((1,))
params = [w, b]
# 之后需要不断地更新w,b,更新模型
for param in params:
    param.attach_grad()


# 定义模型
def net(x):
    return nd.dot(x, w) + b


print(net(data))


# 损失函数,用来衡量预测值与真实值的差距
# 一般使用平方误差来衡量
def square_loss(yhat, y):
    return (yhat - y.reshape(yhat.shape)) ** 2  # 加入reshape的作用是防止yhat是行,而y是列这种错误,用reshape进行广播纠错改正


# 优化,sgd函数使用随机梯度下降的算法,最终的目标就是让loss尽可能地小
def sgd(params, lr):
    for param in params:
        param[:] = param - lr * param.grad


# 训练模型
epochs = 5  # 表示为我要对数据扫5遍
learning_rate = 0.001
for e in range(epochs):
    total_loss = 0
    for data, label in data_iter():
        with ad.record():
            output = net(data)
            loss = square_loss(output, label)

        loss.backward()
        sgd(params, learning_rate)  # 优化误差
        total_loss += nd.sum(loss).asscalar()  # 求和,asscalar的作用是让最终值成为浮点数

    print("Epoch %d,average loss: %f" % (e, total_loss / num_examples))#打印出来每一步的平均误差

print(true_w, w)#打印出最终训练之后的w和b与真实的w和b的差距
print(true_b, b)

 更为简便的(使用gluon函数):

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

num_input = 2
num_examples = 1000

true_w = [2, -3.4]
true_b = 4.2

x = nd.random_normal(shape=(num_examples, num_input))
y = true_w[0] * x[:, 0] + true_w[1] * x[:, 1] + true_b
y += 0.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

# 定义模型
net = gluon.nn.Sequential()  # Sequential是一个容器,具有很多层,一开始定义为空
net.add(gluon.nn.Dense(1))
print(f"net:", net)

# 初始化模型
net.initialize()
# 损失函数
square_loss = gluon.loss.L2Loss()
# 优化
trainer = gluon.Trainer(net.collect_params(), 'sgd', {'learning_rate': 0.1})
# 训练
epochs = 5
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))

dense = net[0]
print(true_w, dense.weight.data())
print(true_b, dense.bias.data())

 

图片识别算法 :

 

# 多类->线性回归
from mxnet import gluon
from mxnet import ndarray as nd
import matplotlib.pyplot as plt


def transform(data, label):
    return data.astype('float32') / 255, label.astype('float32')


mnist_train = gluon.data.vision.FashionMNIST(train=True, transform=transform)
mnist_test = gluon.data.vision.FashionMNIST(train=False, transform=transform)

data, label = mnist_train[0]
print("example shape:", data.shape, 'label', label)  # 3d,长宽高


# 打印图片
def show_images(images):
    n = images.shape[0]
    _, figs = plt.subplots(1, n, figsize=(15, 15))
    for i in range(n):
        figs[i].imshow(images[i].reshape((28, 28)).asnumpy())
        figs[i].axes.get_xaxis().set_visible(False)
        figs[i].axes.get_yaxis().set_visible(False)
    plt.show()


def get_text_label(label):
    text_labels = ['t-shirt', 'trouser', 'pullover', 'dress', 'coat',
                   'sandal', 'shirt', 'sneaker', 'bag', 'ankle boot']
    return [text_labels[int(i)] for i in label]


data, label = mnist_train[0:9]
show_images(data)
print(get_text_label(label))

# 数据读取
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=784:
# 该向量的每个元素对应图像中每个像素。由于图像有10个类别,单层神经网络输出层的输出个数为10.
# 因此softmax回归的权重和偏差参数分别为784×10和1×10的矩阵。
num_input = 784
num_output = 10

w = nd.random_normal(shape=(num_input, num_output))
b = nd.random_normal(shape=num_output)

params = [w, b]
for param in params:
    param.attach_grad()
# 定义模型

from mxnet import nd


# 实现softmax运算
# 我们先描述一下对如何对多维NDArray按维度操作。
# 给定一个NDArray矩阵X。我们可以只对其中同一列(axis=0)或同一行(axis=1)的元素求和,并在结果中保留行和列这两个维度(keepdims=True)。
# 矩阵X的行数是样本数,列数是输出个数。为了表达样本预测各个输出的概率,softmax运算会先通过exp函数对每个元素做指数运算,
# 再对exp矩阵同行元素求和,最后令矩阵每行各元素与该行元素之和相除。这样一来,最终得到的矩阵每行元素和为1且非负。
# 因此,该矩阵每行都是合法的概率分布。softmax运算的输出矩阵中的任意一行元素代表了一个样本在各个输出类别上的预测概率。
def softmax(x):  # 计算概率,首先概率需要为正,且加起来等于1
    exp = nd.exp(x)  # 绝对值函数
    partition = exp.sum(axis=1, keepdims=True)  # 自动使他们转化为合是1
    return exp / partition


x = nd.random_normal(shape=(2, 5))
x_prob = softmax(x)

print(x)
print(x_prob)
print(x_prob.sum(axis=1))


def net(x):
    return softmax(nd.dot(x.reshape((-1, num_input)), w) + b)  # 把数据输入归一,然后利用y=wx+b


# 优化损失
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()  # 将概率最高的拿出来,然后与数据对比查看是否正确


# argmax是取最大的,mean对矩阵求均值


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)  # 求平均


evaluate_accuracy(test_data, net)
print(evaluate_accuracy(test_data, net))

# 训练模型

import sys

sys.path.append('..')
from mxnet import autograd


# 优化函数
def sgd(params, lr):
    for param in params:
        param[:] = param - lr * param.grad


learning_rate = .1

for epoch in range(10):
    train_acc = 0.
    train_loss = 0.
    for data, label in train_data:
        with autograd.record():
            output = net(data)
            loss = 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 / len(train_data)))

# 最后进行图片识别

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

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

  

多层感知机:

 

# 多层感知机

# 获取数据
import d2lzh
from mxnet import autograd

batch_size = 256
train_data, test_data = d2lzh.load_data_fashion_mnist(batch_size)

# 读入数据
from mxnet import ndarray as nd

num_input = 28 * 28
num_output = 10

num_hidden = 256  # 中间多加了一层
weight_scale = .01

w1 = nd.random_normal(shape=(num_input, num_hidden), scale=weight_scale)
b1 = nd.zeros(num_hidden)

w2 = nd.random_normal(shape=(num_hidden, num_output), scale=weight_scale)
b2 = nd.zeros(num_output)

params = [w1, b1, w2, b2]

for param in params:
    param.attach_grad()


# 激活函数

def relu(x):  # 如果x大于0就返回x,否则返回0
    return nd.maximum(x, 0)


# 定义模型

def net(x):
    x = x.reshape((-1, num_input))
    h1 = relu(nd.dot(x, w1) + b1)
    output = nd.dot(h1, w2) + b2
    return output


# softmax 与 损失熵函数

from mxnet import gluon

softmax_cross_entropy = gluon.loss.SoftmaxCrossEntropyLoss()


def accuracy(y_hat, y):
    return (y_hat.argmax(axis=1) == y.astype('float32')).mean().asscalar()


# 训练

learning_rate = .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()
        d2lzh.sgd(params, learning_rate, batch_size)

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

    test_acc = d2lzh.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 / len(train_data)))

 

模型选择 欠拟合与过拟合:
 
# 模型选择 欠拟合与过拟合

# 创建数据集
from mxnet import autograd
from mxnet import ndarray as nd
from mxnet import gluon

num_train = 100
num_tset = 100

true_w = [1.2, -3.4, 5.6]
true_b = 5.0

# 生成数据集

X = nd.random_normal(shape=(num_train + num_tset, 1))
x = nd.concat(X, nd.power(X, 2), nd.power(X, 3))
y = true_w[0] * x[:, 0] + true_w[1] * x[:, 1] + true_w[2] * x[:, 2] + true_b
y += .1 * nd.random_normal(shape=y.shape)
y_train, y_test = y[:num_train], y[num_train:]
print('X:', X[:5], 'x:', x[:5], 'y:', y[:5])

# 定义训练和测试步骤
import matplotlib as mpl

mpl.rcParams['figure.dpi'] = 120
import matplotlib.pyplot as plt


def square_loss(y_hat, y):
    return (y_hat - y.reshape(y_hat.shape)) ** 2 / 2


def test(net, x, y):
    return square_loss(net(x), y).mean().asscalar()


def train(x_train, x_test, y_train, y_test):
    # 定义模型
    net = gluon.nn.Sequential()
    with net.name_scope():
        net.add(gluon.nn.Dense(1))  # 线性回归模型,只有一个输出单元
    net.initialize()  # 初始化模型的参数

    # 定义训练参数
    learning_rate = 0.01
    epochs = 100
    batch_size = 10

    # 创建数据迭代器
    dataset_train = gluon.data.ArrayDataset(x_train, y_train)
    data_iter_train = gluon.data.DataLoader(dataset_train, batch_size, shuffle=True)

    # 定义优化器和损失函数
    trainer = gluon.Trainer(net.collect_params(), 'sgd', {'learning_rate': learning_rate})
    square_loss = gluon.loss.L2Loss()  # 使用均方误差损失函数

    train_loss = []  # 用于记录训练集上的损失值
    test_loss = []  # 用于记录测试集上的损失值

    # 开始训练模型
    for e in range(epochs):
        for data, label in data_iter_train:
            with autograd.record():
                output = net(data)  # 前向传播计算输出
                loss = square_loss(output, label)  # 计算损失
            loss.backward()  # 反向传播求梯度
            trainer.step(batch_size)  # 更新模型参数

        # 计算并记录每个epoch结束后的训练集和测试集上的损失值
        train_loss.append(square_loss(net(x_train), y_train).mean().asscalar())
        test_loss.append(square_loss(net(x_test), y_test).mean().asscalar())

    # 绘制训练集和测试集上的损失曲线
    plt.plot(train_loss)
    plt.plot(test_loss)
    plt.legend(['train', 'test'])
    plt.show()

    # 返回学到的权重和偏置
    return ('learned weight', net[0].weight.data(),
            'learned bias', net[0].bias.data())


# 三阶多项式拟合-正常

train(x[:num_train, :], x[num_train:, :], y[:num_train], y[num_train:])

# 欠拟合 -->数据不够

train(X[:num_train, :], X[num_train:, :], y[:num_train], y[num_train:])

# 过拟合 -->训练量不足

train(x[0:2, :], x[num_train:, :], y[0:2], y[num_train:])

 

正规化(用于减轻数据负担):

# 导入所需的模块
from mxnet import ndarray as nd  # 导入ndarray模块,并指定别名nd
from mxnet import autograd  # 导入autograd模块
import random  # 导入random模块用于生成随机数
import matplotlib as mpl  # 导入matplotlib模块,并指定别名mpl,用于绘图

mpl.rcParams['figure.dpi'] = 120  # 设置matplotlib的图像dpi
import matplotlib.pyplot as plt  # 导入matplotlib.pyplot模块,并指定别名plt,用于绘图

# 定义训练数据集大小、测试数据集大小和输入特征的维度
num_train = 20
num_test = 100
num_input = 200

# 定义真实权重和偏置
true_w = nd.ones((num_input, 1)) * 0.01
true_b = 0.05

# 生成随机数据集x和对应的真实标签y
x = nd.random_normal(shape=(num_train + num_test, num_input))
y = nd.dot(x, true_w)
y += .01 * nd.random_normal(shape=y.shape)

# 划分训练集和测试集
x_train, x_test = x[:num_train, :], x[num_train:, :]
y_train, y_test = y[:num_train], y[num_train:]

# 定义每个批次的大小
batch_size = 1


# 数据迭代器函数,用于按批次随机返回数据和标签
def data_iter(num_example):
    idx = list(range(num_example))
    random.shuffle(idx)
    for i in range(0, num_example, batch_size):
        j = nd.array(idx[i:min(i + batch_size, num_example)])
        yield x.take(j), y.take(j)


# 初始化模型参数(权重和偏置)
def get_params():
    # 随机初始化权重,形状为(num_input, 1)
    w = nd.random_normal(shape=(num_input, 1)) * 0.01
    # 初始化偏置为0,形状为(1,)
    b = nd.zeros((1,))
    for param in (w, b):
        # 为参数附加梯度
        param.attach_grad()
    return (w, b)


# 定义线性回归模型,带有L2正则化
def net(x, lambd, w, b):
    # 返回输入特征x与权重w的乘积再加上偏置b
    return nd.dot(x, w) + b


# 定义平方损失函数
def square_loss(y_hat, y):
    # 计算预测值y_hat与真实标签y之间的平方差
    return (y_hat - y.reshape(y_hat.shape)) ** 2


# 定义随机梯度下降(SGD)优化算法
def sgd(params, lr):
    # 遍历所有参数,对每个参数应用梯度下降算法
    for param in params:
        param[:] = param - lr * param.grad


# 在给定的数据集上测试模型的性能
def test(params, x, y):
    # 计算模型在数据集x上的预测值与真实标签y之间的平方损失均值,并转换为标量
    return square_loss(net(x, 0, *params), y).mean().asscalar()


# 训练高维线性回归模型
def train(lambd):
    # 定义训练迭代次数
    epochs = 10
    # 定义学习率
    learning_rate = 0.003
    # 初始化模型参数
    params = get_params()
    # 记录训练集和测试集上的损失值
    train_loss = []
    test_loss = []
    for e in range(epochs):
        # 对训练数据进行随机打乱,并按批次进行训练
        for data, label in data_iter(num_train):
            with autograd.record():
                # 计算当前模型在训练数据上的预测值
                output = net(data, lambd, *params)
                # 获取权重和偏置参数
                (w, b) = params
                # 计算损失值,包含平方损失和L2正则化项
                loss = square_loss(output, label) + lambd * ((w ** 2).sum() + b ** 2)
            # 计算损失值对模型参数的梯度
            loss.backward()
            # 使用SGD算法更新模型参数
            sgd(params, learning_rate)
        # 计算当前迭代中模型在训练集和测试集上的损失值,并记录到列表中
        train_loss.append(test(params, x_train, y_train))
        test_loss.append(test(params, x_test, y_test))
    # 绘制损失曲线
    plt.plot(train_loss)
    plt.plot(test_loss)
    plt.legend(['train', 'test'])
    plt.show()
    # 打印学习后的权重和偏置的前10个元素
    print('learned w[:10]', params[0][:10], 'learned b:', params[1])


# 观察过拟合,此时没有使用正则化
train(0)

# 观察加入L2正则化后的效果
train(2)

 

Kaggle 房价预测模型:

import d2lzh as d2l
from mxnet import autograd, gluon, init, nd
from mxnet.gluon import data as gdata, loss as gloss, nn
import numpy as np
import pandas as pd

train_data = pd.read_csv(r'C:\Users\ROG\Downloads\train.csv')
test_data = pd.read_csv(r'C:\Users\ROG\Downloads\test.csv')

print(train_data.shape)
print(test_data.shape)
print(train_data.iloc[0:4, [0, 1, 2, 3, -3, -2, -1]])

all_features = pd.concat((train_data.iloc[:, 1:-1], test_data.iloc[:, 1:]))  # 不包含id这一特征

# 预处理数据集
# 我们对连续数值的特征做标准化(standardization):
# 设该特征在整个数据集上的均值为μ,标准差为σ。那么,我们可以将该特征的每个值先减去μ再除以σ得到标准化后的每个特征值。
# 对于缺失的特征值,我们将其替换成该特征的均值。

numeric_features = all_features.dtypes[all_features.dtypes != 'object'].index
all_features[numeric_features] = all_features[numeric_features].apply(
    lambda x: (x - x.mean()) / (x.std()))
# 标准化后,每个特征的均值变为0,所以可以直接用0来替换缺失值
all_features[numeric_features] = all_features[numeric_features].fillna(0)

# dummy_na=True将缺失值也当作合法的特征值并为其创建指示特征
all_features = pd.get_dummies(all_features, dummy_na=True)
print(all_features.shape)

# 通过values属性得到NumPy格式的数据,并转成NDArray方便后面的训练。

n_train = train_data.shape[0]  # id
train_features = nd.array(all_features[:n_train].values)
test_features = nd.array(all_features[n_train:].values)
train_labels = nd.array(train_data.SalePrice.values).reshape((-1, 1))

# 训练模型

# 定义均方误差损失函数
loss = gloss.L2Loss()


def get_net():
    # 创建一个简单的线性回归模型
    net = nn.Sequential()
    net.add(nn.Dense(1))  # 添加一个全连接层,输出大小为1
    net.initialize()  # 初始化网络参数
    return net


def log_rmse(net, features, labels):
    # 计算均方根误差(RMSE)
    clipped_preds = nd.clip(net(features), 1, float('inf'))  # 对模型预测值进行裁剪,限制在[1, 正无穷)
    rmse = nd.sqrt(2 * loss(clipped_preds.log(), labels.log()).mean())  # 计算预测值与标签之间的RMSE
    # 在这段代码中,我们可以观察到在计算RMSE时,对MSE进行了缩放,乘以了2。这是因为MSE的计算通常被除以样本数N来取平均值。
    # 但是,为了方便计算梯度,通过乘以2可以将除法操作合并到平方根中,避免了对损失函数进行求导时出现分母的情况。
    # 所以,乘以2不会改变RMSE的相对大小,但在计算梯度时更方便。最终返回的RMSE值也是一个合理的评估指标,只是相对于未乘以2的RMSE值要大一倍。
    # 在比较不同模型或优化算法时,具有相同缩放因子的RMSE是等价的,因为它们都能提供相同的信息。
    return rmse.asscalar()  # 将RMSE转换为标量(Python中的普通浮点数)并返回


def train(net, train_features, train_labels, test_features, test_labels,
          num_epochs, learning_rate, weight_decay, batch_size):
    train_is, test_is = [], []
    train_iter = gdata.DataLoader(gdata.ArrayDataset(train_features, train_labels), batch_size, shuffle=True)
    # 创建一个训练集的数据迭代器,用于在训练过程中批量获取数据

    # 创建Adam优化器
    # 训练函数与本章中前几节的不同在于使用了Adam优化算法
    # 相对之前使用的小批量随机梯度下降,它对学习率相对不那么敏感
    trainer = gluon.Trainer(net.collect_params(), 'adam', {
        'learning_rate': learning_rate, 'wd': weight_decay})

    for epoch in range(num_epochs):
        # 开始对训练数据进行多轮迭代,每轮迭代称为一个epoch
        for data, label in train_iter:
            # 通过训练集迭代器获取一个批次的训练数据和对应的标签

            with autograd.record():
                # 开启自动求导功能,在这个上下文中,所有在此处定义的计算操作将被记录下来,以便后续进行反向传播和梯度计算
                _loss = loss(net(data), label)
                # 计算当前批次数据的损失值

            _loss.backward()
            # 执行反向传播,计算出当前批次数据的梯度,反向传播的结果将被存储在每个参数的.grad属性中

            trainer.step(batch_size)
            # 使用优化器更新网络参数,trainer.step(batch_size)将会更新每个参数的值,使其沿着梯度的反方向移动一小步,batch_size用于梯度归一化

        # 计算当前epoch结束后,在训练集上的均方根误差(RMSE)并添加到列表中
        train_is.append(log_rmse(net, train_features, train_labels))

        if test_labels is not None:
            # 如果提供了测试集的标签,则计算当前epoch结束后,在测试集上的均方根误差(RMSE)并添加到列表中
            test_is.append(log_rmse(net, test_features, test_labels))

    return train_is, test_is
    # 返回两个列表train_is和test_is,分别包含每个epoch结束后在训练集和测试集上计算得到的RMSE值


# k 折交叉验证
def get_k_fold_data(k, i, x, y):
    # 函数用于获取第i折交叉验证时的训练集和验证集
    assert k > 1  # 确保k的取值大于1

    fold_size = x.shape[0] // k  # 计算每折的样本数
    x_train, y_train = None, None

    for j in range(k):
        # 遍历k折数据
        idx = slice(j * fold_size, (j + 1) * fold_size)  # 计算当前折的数据索引范围
        x_part, y_part = x[idx, :], y[idx]  # 获取当前折的特征和标签

        if j == i:
            x_valid, y_valid = x_part, y_part  # 当前折作为验证集
        elif x_train is None:
            x_train, y_train = x_part, y_part  # 第一折作为训练集
        else:
            x_train = nd.concat(x_train, x_part, dim=0)  # 将后续的折数据拼接到训练集
            y_train = nd.concat(y_train, y_part, dim=0)

    return x_train, y_train, x_valid, y_valid  # 返回训练集和验证集的特征和标签


def k_fold(k, x_train, y_train, num_epochs, learning_rate, weight_decay, batch_size):
    # 对数据进行k折交叉验证
    train_l_sum, valid_l_sum = 0, 0

    for i in range(k):
        # 对每折数据进行训练和验证
        data = get_k_fold_data(k, i, x_train, y_train)
        net = get_net()  # 创建一个新的模型

        train_ls, valid_ls = train(net, *data, num_epochs, learning_rate, weight_decay, batch_size)
        # 对当前模型在训练集和验证集上进行训练,并返回训练集和验证集上的均方根误差(RMSE)值
        train_l_sum += train_ls[-1]  # 累加每折训练集上的最后一个RMSE值
        valid_l_sum += valid_ls[-1]  # 累加每折验证集上的最后一个RMSE值

        if i == 0:
            # 绘制第一折的训练集和验证集上RMSE随epoch变化的图形
            d2l.semilogy(range(1, num_epochs + 1), train_ls, 'epochs', 'rmse',
                         range(1, num_epochs + 1), valid_ls,
                         ['train', 'valid'])

        print('fold %d, train rmse %f, valid rmse %f'
              % (i, train_ls[-1], valid_ls[-1]))
        # 打印每折训练和验证结束时的RMSE值

    return train_l_sum / k, valid_l_sum / k
    # 返回k折交叉验证结束后的平均训练集和验证集上的RMSE值


# 模型选择
k, num_epochs, lr, weight_decay, batch_size = 5, 10000, 5, 0, 64
# 设置交叉验证折数k,训练轮数num_epochs,学习率lr,权重衰减weight_decay和批量大小batch_size
train_l, valid_l = k_fold(k, train_features, train_labels, num_epochs, lr, weight_decay, batch_size)
# 对训练数据进行k折交叉验证,得到训练集和验证集上的平均RMSE值
print('%d-fold validation: avg train rmse %f, avg valid rmse %f'
      % (k, train_l, valid_l))
# 打印k折交叉验证结束后的平均训练集和验证集上的RMSE值


# 定义预测函数
def train_and_pred(train_features, test_features, train_labels, test_data,
                   num_epochs, lr, weight_decay, batch_size):
    # 训练模型并进行预测
    net = get_net()  # 创建一个新的模型
    train_is, _ = train(net, train_features, train_labels, None, None,
                        num_epochs, lr, weight_decay, batch_size)
    # 对训练集进行训练,并返回训练集上的均方根误差(RMSE)值

    d2l.semilogy(range(1, num_epochs + 1), train_is, 'epochs', 'rmse')
    # 绘制训练集上RMSE随epoch变化的图形

    print('train rmse %f' % train_is[-1])
    # 打印训练结束时的RMSE值

    preds = net(test_features).asnumpy()
    # 对测试集进行预测
    test_data['SalePrice'] = pd.Series(preds.reshape(1, -1)[0])
    # 将预测结果转换为pandas Series格式

    submission = pd.concat([test_data['Id'], test_data['SalePrice']], axis=1)
    # 拼接测试集的Id和预测结果
    submission.to_csv('submission.csv', index=False)
    # 将结果保存为CSV文件


# 预测
train_and_pred(train_features, test_features, train_labels, test_data,
               num_epochs, lr, weight_decay, batch_size)
# 进行预测并保存结果到submission.csv文件

 

填充与步幅:

# 填充和步幅

from mxnet import nd
from mxnet.gluon import nn


# 填充
# (nh−kh+ph+1)×(nw−kw+pw+1),
# 也就是说,输出的高和宽会分别增加ph和pw。
#
# 在很多情况下,我们会设置ph=kh−1和pw=kw−1来使输入和输出具有相同的高和宽。
# 这样会方便在构造网络时推测每个层的输出形状。假设这里kh是奇数,我们会在高的两侧分别填充ph/2行。
# 如果kh是偶数,一种可能是在输入的顶端一侧填充⌈ph/2⌉行,而在底端一侧填充⌊ph/2⌋行。在宽的两侧填充同理。

def comp_conv2d(conv2d, x):
    conv2d.initialize()  # 初始化
    x = x.reshape((1, 1) + x.shape)  # Conv2D函数是思维的卷积,所以要先加上两个维度,返回时只返回后两个维度就可以
    y = conv2d(x)
    return y.reshape(y.shape[2:])  # 返回后两个维度


conv2d = nn.Conv2D(1, kernel_size=3, padding=1)  # padding 代表填充数,如果填充1个也就上下填充1,总数是2

x = nd.random.uniform(shape=(8, 8))
print(comp_conv2d(conv2d, x).shape)

conv2d = nn.Conv2D(1, kernel_size=(5, 3), padding=(2, 1))
print(comp_conv2d(conv2d, x).shape)

# 步幅


# 一般来说,当高上步幅为sh,宽上步幅为sw时,输出形状为
#
# ⌊(nh−kh+ph+sh)/sh⌋×⌊(nw−kw+pw+sw)/sw⌋.
# 如果设置ph=kh−1和pw=kw−1,那么输出形状将简化为⌊(nh+sh−1)/sh⌋×⌊(nw+sw−1)/sw⌋。
# 更进一步,如果输入的高和宽能分别被高和宽上的步幅整除,那么输出形状将是(nh/sh)×(nw/sw)。


conv2d = nn.Conv2D(1, kernel_size=3, padding=1, strides=2)  # strides是步幅,这里指高和宽全是2
print(comp_conv2d(conv2d, x).shape)

conv2d = nn.Conv2D(1, kernel_size=3, padding=(0, 1), strides=(3, 4))
print(comp_conv2d(conv2d, x).shape)

 

多输入通道和多输出通道:

# 多输入通道和多输出通道


import d2lzh as d2l
from mxnet import nd


# 多输入通道和多输出通道

def corr2d_multi_in(X, K):
    # 首先沿着X和K的第0维(通道维)遍历。然后使用*将结果列表变成add_n函数的位置参数
    # (positional argument)来进行相加
    return nd.add_n(*[d2l.corr2d(x, k) for x, k in zip(X, K)])


X = nd.array([[[0, 1, 2], [3, 4, 5], [6, 7, 8]],
              [[1, 2, 3], [4, 5, 6], [7, 8, 9]]])
K = nd.array([[[0, 1], [2, 3]], [[1, 2], [3, 4]]])

y = corr2d_multi_in(X, K)
print(y)


# 多输出通道
# 当输入通道有多个时,因为我们对各个通道的结果做了累加,所以不论输入通道数是多少,输出通道数总是为1。
# 设卷积核输入通道数和输出通道数分别为 ci和 co
# 高和宽分别为 kh 和 kw
# 如果希望得到含多个通道的输出,我们可以为每个输出通道分别创建形状为 ci×kh×kw的核数组
# 将它们在输出通道维上连结,卷积核的形状即 co×ci×kh×kw
# 在做互相关运算时,每个输出通道上的结果由卷积核在该输出通道上的核数组与整个输入数组计算而来。
def corr2d_multi_in_out(X, K):
    # 对K的第0维遍历,每次同输入X做互相关计算。所有结果使用stack函数合并在一起
    return nd.stack(*[corr2d_multi_in(X, k) for k in K])


K = nd.stack(K, K + 1, K + 2)
print(K.shape)
print(corr2d_multi_in_out(X, K))

# 1×1卷积层:

# 使用全连接层中的矩阵乘法来实现1×1卷积


def corr2d_multi_in_out_1x1(x, k):
    # 获取输入特征图的通道数,高度和宽度
    c_i, h, w = x.shape
    # 获取卷积核的输出通道数
    c_o = k.shape[0]

    # 将输入特征图转换为二维张量,每个位置 (i, j) 处的像素值作为一个长度为 c_i 的向量
    x = x.reshape((c_i, h * w))
    # 将卷积核转换为二维张量,用于后续全连接层的矩阵乘法
    k = k.reshape((c_o, c_i))

    # 进行全连接层的矩阵乘法,得到形状为 (c_o, h * w) 的输出
    y = nd.dot(k, x)
    # 将输出特征图转换回三维张量,形状为 (c_o, h, w)
    return y.reshape((c_o, h, w))


x = nd.random.uniform(shape=(3, 3, 3))  # 生成一个 3x3x3 的输入特征图
k = nd.random.uniform(shape=(2, 3, 1, 1))  # 生成一个 2x3x1x1 的卷积核

# 使用 corr2d_multi_in_out_1x1 函数进行 1x1 卷积
y1 = corr2d_multi_in_out_1x1(x, k)

# 使用 corr2d_multi_in_out 函数进行普通卷积(包括填充和步幅的卷积)
y2 = corr2d_multi_in_out(x, k)

# 检查两种卷积方法的输出是否非常接近(误差小于 1e-6)
print((y1 - y2).norm().asscalar() < 1e-6)

 

posted @ 2023-07-31 16:02  o-Sakurajimamai-o  阅读(65)  评论(0)    收藏  举报
-- --