深度学习小记00--神经元的工作原理与简单代码实现


本系列博客用于记录学习深度学习的过程。

一、神经元的基本模型

神经元基本模型
如图所示是一个神经元的基本模型,神经元在训练时的主要步骤分为蓝色线(前向传播)和红色线(反向传播–梯度下降)。约定符号:X11表示第一个样本的第一个特征值,X1表示第一个样本,Y1表示第一个样本的实际值,A1表示第一个样本的预测值,W1表示加在第一个特征值的权重,W=[W1,W2,…,Wn]

(一)前向传播

如上图所示,前向传播的过程分为3个或4个步骤(平均损失值的计算)。
1.假设神经元有N个特征值输入,则通过初始化W和B构造一个线性关系(N+1维线性超平面)。
2.对上面关系进行第二次映射(一般是非线性的)得到预测值A。(激励函数的作用下)
3.通过损失函数评估预测值和实际值之间的距离。(类似于统计学中方差的作用)
4.计算出全部样本通过W和B变换后且通过激励函数后的预测值与实际值的距离并取其平均值作为参考。(在后面的训练中该值正常情况下应越来越小)

(二)反向传播–梯度下降法

在整个神经元的前向传播中,我们可以分析出损失平均值J可以表示如以下形式。J=F(L),J=F(A,Y),J=F(Z,Y),J=F(W,B,Y)。所以我们可以看出损失函数在根本上是跟W和B的取值有关的。在神经网络的训练中,我们的目的是想要让实际值和预测值之间的距离减少,这意味着我们想要让得到的J值下降。
在这里插入图片描述
假设损失函数的图像如上为y=x²,即y=F(x),我们可以通过y对x求导,得到y对x的导数,根据导数的定义,导数为与图像相切的直线,当导数为正时,即x=x+导数乘以一个正数,y值增加,x=x+导数乘以一个负数,y值减少。所以我们可以通过损失函数L对其参数W进行更新,即W= W+dL/dWα(α<0)对其参数B进行更新,即B= B+ dL/dBα(α<0),可以使得损失函数值下降,从而到达我们想要的预测值与实际值之间距离减少的目的。而dL/dW,dL/dB可以通过上图神经元模型中红色线得到,即在设计神经元时,先初始化dL/dA,dA/dZ,dZ/dW,dZ/dB(这些是在整个过程中不变的表达式,所以可以轻易地设计出来),再通过样本的输入动态的调整W和B。

PS:一次训练更新一次W和B,所以设计上是将所有样本的dW平均值作为W的更新,所有样本的dB取平均值作为B的更新。

(三)为什么需要进行线性拟合再做非线性映射(激励函数)?

在这里插入图片描述
如上图所示,如果直接采用非线性的函数,在某些区间中函数值变化对于参数的变化的敏感度很低,会导致梯度消失或者梯度下降缓慢的现象。

如果只采用线性的函数,就不能很好的拟合出现实中的实际问题(一般实际问题不会是线性的关系),另一方面,深度学习是通过建立多层次的神经网络去获取特征与实际值Y之间深层次的关系,如果每个神经层都是线性的,那么深度高的神经网络与深度低的神经网络本质上可能没有什么区别。

二、python代码实现

基本神经元

class basic_neuron:

    def __init__(self, W, X, B, activity_func, dA_dZ, loss_func, Y, alfa, print_accuracy=True):
        """
        设count(X) = n, Xn = m,即特征值个数为m,样本数为n
        :param W: shape == 1*Xn
        :param X: shape = Xn*n
        :param B: shape = 1*Xn
        :param activity_func: 激活函数 返回激活函数计算后的值A
        :param dA_dZ 返回 dA(激活函数)/dZ 的 函数
        :param loss_func: 损失函数 返回用于梯度下降的dW,dB,accuracy,total_loss
        :param Y: 实际值
        :param alfa:学习率
        :param print_accuracy:是否打印准确度
        """
        self.W = W.astype('float64')
        self.X = X.astype('float64')
        self.B = B
        self.activity_fun = activity_func
        self.loss_func = loss_func
        self.Y = Y.astype('float64')
        self.alfa = -alfa
        self.print_accuracy = print_accuracy
        self.dA_dZ = dA_dZ

    def change_param(self, dW, dB):
        self.W += self.alfa * dW
        self.B += self.alfa * dB

    def calculate_yp(self):
        return self.activity_fun(np.dot(self.W, self.X) + self.B)

    def run(self):
        YP = self.calculate_yp()
        dA, accuracy, total_loss = self.loss_func(YP, self.Y)
        Z = np.dot(self.W, X) + self.B
        dZ = np.multiply(dA, self.dA_dZ(Z))
        dW = np.dot(dZ, self.X.T) / self.X.shape[1]
        dB = dZ.sum(axis=1, keepdims=True) / self.X.shape[1]
        # print('/*------------------------------*/')
        # print('YP:',YP)
        # print('dW:',dW,'dB:',dB)
        # print('Loss:',total_loss)
        # print('/*------------------------------*/')
        self.change_param(dW, dB)
        if self.print_accuracy:
            print('accuracy:', accuracy)
        print('Loss:', total_loss)

    def predict(self, X):
        return self.activity_fun(np.dot(self.W, X) + self.B)

基本损失函数和激活函数

def activity_func(Z):
    # sigmoid函数
    yp = 1 / (1 + np.exp(-1 * Z))
    return yp


def dA_dZ(Z):
    # 返回sigmoid函数的导数
    return np.multiply((1 / (1 + np.exp(-1 * Z))), (1 - (1 / (1 + np.exp(-1 * Z)))))


def loss_func(YP, Y):
    size = YP.shape[1]  # 得到YP的数量
    Y_arr = Y.tolist()
    YP_arr = YP.tolist()
    # 避免后续求dA出现除0现象
    temp = np.where(YP == 1)
    for index, item in enumerate(temp[0]):
        YP[item, temp[1][index]] = 0.999999999999

    dA = -(np.true_divide(Y, YP) + np.true_divide((Y - 1), (1 - YP)))
    loss_part1 = np.dot(Y, np.log(YP).T)
    loss_part2 = np.dot(1 - Y, np.log(1 - YP).T)
    loss = -(loss_part1 + loss_part2)
    count = 0
    for index, item in enumerate(Y_arr[0]):
        if abs(item - YP_arr[0][index]) < 0.5:
            count += 1
    accuracy = count / size
    return dA, accuracy, float(loss) / size

运行代码

if __name__ == '__main__':
    # 生成训练集,X1<100,X2>100为1类,X1>100,X2<100为1类
    X_list = []
    for i in range(200):
        if i < 100:
            temp1 = random.random() * 100
            temp2 = 100 + random.random() * 100
        else:
            temp1 = 100 + random.random() * 100
            temp2 = random.random() * 100
        X_list.append([temp1, temp2])
    Y_list = []
    for i in range(200):
        Y_list.append(1 if i < 100 else 0)
    # 初始化参数
    W = np.array([[0, 0]]).astype('float64').reshape(1, 2)
    B = 0
    X = np.array(X_list).T
    Y = np.array(Y_list).reshape(1, 200)
    alfa = 0.01
    # 生成神经元
    neuron = basic_neuron(W, X, B, activity_func, dA_dZ, loss_func, Y, alfa)
    # 迭代训练
    for i in range(3):
        neuron.run()
    # 进行检测
    pre = neuron.predict(np.array([[120], [30]]).reshape([2, 1]))
    print(pre)

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,以下是使用PyTorch实现 "Learning a Deep ConvNet for Multi-label Classification with Partial Labels" 论文的示例代码。 ```python import torch import torch.nn as nn import torch.optim as optim from torch.utils.data import DataLoader from torchvision.transforms import transforms from sklearn.metrics import f1_score from dataset import CustomDataset from model import ConvNet # 设置随机数种子,保证结果可重复 torch.manual_seed(2022) # 定义超参数 epochs = 50 batch_size = 128 learning_rate = 0.001 weight_decay = 0.0001 num_classes = 20 num_labels = 3 # 定义数据预处理 transform = transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)) ]) # 加载数据集 train_dataset = CustomDataset(root='./data', split='train', transform=transform) train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True, num_workers=2) test_dataset = CustomDataset(root='./data', split='test', transform=transform) test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False, num_workers=2) # 定义模型 model = ConvNet(num_classes=num_classes, num_labels=num_labels) # 定义损失函数和优化器 criterion = nn.BCEWithLogitsLoss() optimizer = optim.Adam(model.parameters(), lr=learning_rate, weight_decay=weight_decay) # 训练模型 for epoch in range(epochs): # 训练阶段 model.train() running_loss = 0.0 for i, data in enumerate(train_loader): inputs, labels = data optimizer.zero_grad() outputs = model(inputs) loss = criterion(outputs, labels) loss.backward() optimizer.step() running_loss += loss.item() train_loss = running_loss / len(train_loader) # 测试阶段 model.eval() y_true, y_pred = [], [] with torch.no_grad(): for data in test_loader: inputs, labels = data outputs = model(inputs) predicted_labels = torch.round(torch.sigmoid(outputs)) y_true.extend(labels.cpu().numpy()) y_pred.extend(predicted_labels.cpu().numpy()) f1 = f1_score(y_true, y_pred, average='macro') print('[Epoch %d] Train Loss: %.3f, Test F1: %.3f' % (epoch + 1, train_loss, f1)) ``` `CustomDataset` 和 `ConvNet` 分别是数据集类和模型类,需要根据您的具体情况进行实现。在训练阶段,使用 `nn.BCEWithLogitsLoss()` 作为损失函数进行优化。在测试阶段,使用 `sklearn.metrics.f1_score()` 计算 F1 值作为模型评估指标。 希望以上示例代码对您有所帮助!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值