NNDL 实验四 线性分类

第3章 线性分类
3.1 基于Logistic回归的二分类任务
3.1.1 数据集构建
构建一个简单的分类任务,并构建训练集、验证集和测试集。
本任务的数据来自带噪音的两个弯月形状函数,每个弯月对一个类别。我们采集1000条样本,每个样本包含2个特征。

随机采集1000个样本,并进行可视化。

将1000条样本数据拆分成训练集、验证集和测试集,其中训练集640条、验证集160条、测试集200条。

import math
import copy
import torch as tr


def make_moons(n_samples=1000, shuffle=True, noise=None):
    """
    生成带噪音的弯月形状数据
    输入:
        - n_samples:数据量大小,数据类型为int
        - shuffle:是否打乱数据,数据类型为bool
        - noise:以多大的程度增加噪声,数据类型为None或float,noise为None时表示不增加噪声
    输出:
        - X:特征数据,shape=[n_samples,2]
        - y:标签数据, shape=[n_samples]
    """
    n_samples_out = n_samples // 2
    n_samples_in = n_samples - n_samples_out

    # 采集第1类数据,特征为(x,y)
    # 使用'tr.linspace'在0到pi上均匀取n_samples_out个值
    # 使用'tr.cos'计算上述取值的余弦值作为特征1,使用'paddle.sin'计算上述取值的正弦值作为特征2
    outer_circ_x = tr.cos(tr.linspace(0, math.pi, n_samples_out))
    outer_circ_y = tr.sin(tr.linspace(0, math.pi, n_samples_out))

    inner_circ_x = 1 - tr.cos(tr.linspace(0, math.pi, n_samples_in))
    inner_circ_y = 0.5 - tr.sin(tr.linspace(0, math.pi, n_samples_in))

    print('outer_circ_x.shape:', outer_circ_x.shape, 'outer_circ_y.shape:', outer_circ_y.shape)
    print('inner_circ_x.shape:', inner_circ_x.shape, 'inner_circ_y.shape:', inner_circ_y.shape)

    # 使用'tr.concat'将两类数据的特征1和特征2分别延维度0拼接在一起,得到全部特征1和特征2
    # 使用'tr.stack'将两类特征延维度1堆叠在一起
    X = tr.stack(
        [tr.cat([outer_circ_x, inner_circ_x]),
         tr.cat([outer_circ_y, inner_circ_y])],
       1
    )

    print('after concat shape:', tr.cat([outer_circ_x, inner_circ_x]).shape)
    print('X shape:', X.shape)

    # 使用'tr. zeros'将第一类数据的标签全部设置为0
    # 使用'tr. ones'将第一类数据的标签全部设置为1
    y = tr.cat(
        [tr.zeros(size=[n_samples_out]), tr.ones(size=[n_samples_in])]
    )

    print('y shape:', y.shape)

    # 如果shuffle为True,将所有数据打乱
    if shuffle:
        # 使用'tr.randperm'生成一个数值在0到X.shape[0],随机排列的一维Tensor做索引值,用于打乱数据
        idx = tr.randperm(X.shape[0])
        X = X[idx]
        y = y[idx]

    # 如果noise不为None,则给特征值加入噪声
    if noise is not None:
        # 使用'tr.normal'生成符合正态分布的随机Tensor作为噪声,并加到原始特征上
        X += tr.normal(0.0, noise, X.shape)

    return X, y


# 采样1000个样本
n_samples = 1000
X, y = make_moons(n_samples=n_samples, shuffle=True, noise=0.5)
# 可视化生产的数据集,不同颜色代表不同类别
#matplotlib inline
import matplotlib.pyplot as plt

plt.figure(figsize=(5,5))
plt.scatter(x=X[:, 0].tolist(), y=X[:, 1].tolist(), marker='*', c=y.tolist())
plt.xlim(-3,4)
plt.ylim(-3,4)
plt.savefig('linear-dataset-vis.pdf')
plt.show()

num_train = 640
num_dev = 160
num_test = 200

X_train, y_train = X[:num_train], y[:num_train]
X_dev, y_dev = X[num_train:num_train + num_dev], y[num_train:num_train + num_dev]
X_test, y_test = X[num_train + num_dev:], y[num_train + num_dev:]

y_train = y_train.reshape([-1,1])
y_dev = y_dev.reshape([-1,1])
y_test = y_test.reshape([-1,1])

# 打印X_train和y_train的维度
print("X_train shape: ", X_train.shape, "y_train shape: ", y_train.shape)

# 打印一下前5个数据的标签
print (y_train[:5])
C:\Users\320\PycharmProjects\pythonProject\venv\Scripts\python.exe C:/Users/320/PycharmProjects/pythonProject/main.py
outer_circ_x.shape: torch.Size([500]) outer_circ_y.shape: torch.Size([500])
inner_circ_x.shape: torch.Size([500]) inner_circ_y.shape: torch.Size([500])
after concat shape: torch.Size([1000])
X shape: torch.Size([1000, 2])
y shape: torch.Size([1000])
X shape: torch.Size([1000, 2])
y shape: torch.Size([1000])
X_train shape:  torch.Size([640, 2]) y_train shape:  torch.Size([640, 1])
tensor([[1.],
        [1.],
        [1.],
        [0.],
        [0.]])

3.1.2 模型构建

# 定义Logistic函数
def logistic(x):
    return 1 / (1 + tr.exp(-x))

# 在[-10,10]的范围内生成一系列的输入值,用于绘制函数曲线
x = tr.linspace(-10, 10, 10000)
plt.figure()
plt.plot(x.tolist(), logistic(x).tolist(), color="#e4007f", label="Logistic Function")
# 设置坐标轴
ax = plt.gca()
# 取消右侧和上侧坐标轴
ax.spines['top'].set_color('none')
ax.spines['right'].set_color('none')
# 设置默认的x轴和y轴方向
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')
# 设置坐标原点为(0,0)
ax.spines['left'].set_position(('data',0))
ax.spines['bottom'].set_position(('data',0))
# 添加图例
plt.legend()
plt.savefig('linear-logistic.pdf')
plt.show()
from nndl import op

class model_LR(op.Op):
    def __init__(self, input_dim):
        super(model_LR, self).__init__()
        self.params = {}
        # 将线性层的权重参数全部初始化为0
        self.params['w'] = tr.zeros(size=[input_dim, 1])
        # self.params['w'] = paddle.normal(mean=0, std=0.01, shape=[input_dim, 1])
        # 将线性层的偏置参数初始化为0
        self.params['b'] = tr.zeros(size=[1])

    def __call__(self, inputs):
        return self.forward(inputs)

    def forward(self, inputs):
        """
        输入:
            - inputs: shape=[N,D], N是样本数量,D为特征维度
        输出:
            - outputs:预测标签为1的概率,shape=[N,1]
        """
        # 线性计算
        score =tr.matmul(inputs, self.params['w']) + self.params['b']
        # Logistic 函数
        outputs = logistic(score)
        return outputs
# 固定随机种子,保持每次运行结果一致
tr.seed()
# 随机生成3条长度为4的数据
inputs = tr.randn([3,4])
print('Input is:', inputs)
# 实例化模型
model = model_LR(4)
outputs = model(inputs)
print('Output is:', outputs)
Input is: tensor([[-0.0978,  0.5052,  1.3404, -0.8549],
        [ 0.0810, -1.8998, -0.7390,  0.0764],
        [-0.4519, -1.0605,  0.0022,  0.7759]])
Output is: tensor([[0.5000],
        [0.5000],
        [0.5000]])


问题1:Logistic回归在不同的书籍中,有许多其他的称呼,具体有哪些?你认为哪个称呼最好?

答:有罗杰斯蒂克回归分析,罗杰斯蒂回归,逻辑斯特回归,罗吉斯回归,逻辑回归分析。我认为罗杰斯蒂克回归分析更好,因为更直白,发音也更符合Logistic。

问题2:什么是激活函数?为什么要用激活函数?常见激活函数有哪些?

答:激活函数(Activation Function)是一种添加到人工神经网络中的函数,旨在帮助网络学习数据中的复杂模式。在神经元中,输入的input经过一系列加权求和后作用于另一个函数,这个函数就是这里的激活函数。

如果不用激活函数,每一层输出都是上层输入的线性函数,无论神经网络有多少层,输出都是输入的线性组合,这种情况就是最原始的感知机。如果使用的话,激活函数给神经元引入了非线性因素,使得神经网络可以任意逼近任何非线性函数,这样神经网络就可以应用到众多的非线性模型中。总之是将线性模型转换为非线性,使它的适用范围更广了。

常见的激活函数有:Sigmoid函数

Tanh函数

 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值