C 语言实现:深度学习基础

概述

在本节中,我们使用 C 语言 实现深度学习的基础概念:

  1. 人工神经网络(ANN, Artificial Neural Network)
  2. 反向传播算法(Backpropagation)
  3. 卷积神经网络(CNN, Convolutional Neural Network)
  4. 递归神经网络(RNN, Recurrent Neural Network)

1. 人工神经网络(ANN)

1.1 ANN 介绍

ANN 是一种模拟人脑神经元的计算模型
主要结构:

  • 输入层(Input Layer)
  • 隐藏层(Hidden Layer)
  • 输出层(Output Layer)
  • 激活函数(Sigmoid, ReLU)

计算公式

h = sigmoid(W_xh * x + b_h)
y = sigmoid(W_hy * h + b_y)

📌 C 语言实现 ANN

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define INPUT_NODES  2
#define HIDDEN_NODES 2
#define OUTPUT_NODES 1
#define ALPHA 0.1
#define EPOCHS 10000

// Sigmoid 激活函数
float sigmoid(float x) {
    return 1.0 / (1.0 + exp(-x));
}

// Sigmoid 导数
float sigmoid_derivative(float x) {
    return x * (1.0 - x);
}

// ANN 结构
typedef struct {
    float W_xh[HIDDEN_NODES][INPUT_NODES];
    float W_hy[OUTPUT_NODES][HIDDEN_NODES];
    float b_h[HIDDEN_NODES];
    float b_y[OUTPUT_NODES];
} ANN;

// 初始化 ANN
void initializeANN(ANN* ann) {
    for (int i = 0; i < HIDDEN_NODES; i++) {
        for (int j = 0; j < INPUT_NODES; j++) {
            ann->W_xh[i][j] = (float)rand() / RAND_MAX * 2 - 1;
        }
        ann->b_h[i] = 0;
    }

    for (int i = 0; i < OUTPUT_NODES; i++) {
        for (int j = 0; j < HIDDEN_NODES; j++) {
            ann->W_hy[i][j] = (float)rand() / RAND_MAX * 2 - 1;
        }
        ann->b_y[i] = 0;
    }
}

// 前向传播
void forwardANN(ANN* ann, float input[INPUT_NODES], float hidden[HIDDEN_NODES], float output[OUTPUT_NODES]) {
    for (int i = 0; i < HIDDEN_NODES; i++) {
        hidden[i] = ann->b_h[i];
        for (int j = 0; j < INPUT_NODES; j++) {
            hidden[i] += ann->W_xh[i][j] * input[j];
        }
        hidden[i] = sigmoid(hidden[i]);
    }

    for (int i = 0; i < OUTPUT_NODES; i++) {
        output[i] = ann->b_y[i];
        for (int j = 0; j < HIDDEN_NODES; j++) {
            output[i] += ann->W_hy[i][j] * hidden[j];
        }
        output[i] = sigmoid(output[i]);
    }
}

实现 ANN 结构、前向传播
适用于分类、回归任务


2. 反向传播算法(Backpropagation)

2.1 反向传播原理

计算误差

error = target - output

更新权重

W_new = W_old + α * error * 输入

📌 C 语言实现反向传播

// 反向传播
void backwardANN(ANN* ann, float input[INPUT_NODES], float hidden[HIDDEN_NODES], float output[OUTPUT_NODES], float target[OUTPUT_NODES]) {
    float outputError[OUTPUT_NODES], hiddenError[HIDDEN_NODES];

    for (int i = 0; i < OUTPUT_NODES; i++) {
        outputError[i] = (target[i] - output[i]) * sigmoid_derivative(output[i]);
    }

    for (int i = 0; i < HIDDEN_NODES; i++) {
        hiddenError[i] = 0;
        for (int j = 0; j < OUTPUT_NODES; j++) {
            hiddenError[i] += outputError[j] * ann->W_hy[j][i];
        }
        hiddenError[i] *= sigmoid_derivative(hidden[i]);
    }

    for (int i = 0; i < OUTPUT_NODES; i++) {
        for (int j = 0; j < HIDDEN_NODES; j++) {
            ann->W_hy[i][j] += ALPHA * outputError[i] * hidden[j];
        }
        ann->b_y[i] += ALPHA * outputError[i];
    }

    for (int i = 0; i < HIDDEN_NODES; i++) {
        for (int j = 0; j < INPUT_NODES; j++) {
            ann->W_xh[i][j] += ALPHA * hiddenError[i] * input[j];
        }
        ann->b_h[i] += ALPHA * hiddenError[i];
    }
}

适用于训练 ANN, CNN, RNN


3. CNN(卷积神经网络)基础

3.1 CNN 结构

核心组件

  • 卷积层(Convolution)
  • 池化层(Pooling)
  • 全连接层(Fully Connected)
    适用于图像处理

📌 C 语言实现 CNN

#define INPUT_SIZE 5
#define KERNEL_SIZE 3
#define OUTPUT_SIZE (INPUT_SIZE - KERNEL_SIZE + 1)

// 卷积操作
void convolution(float input[INPUT_SIZE][INPUT_SIZE], float kernel[KERNEL_SIZE][KERNEL_SIZE], float output[OUTPUT_SIZE][OUTPUT_SIZE]) {
    for (int i = 0; i < OUTPUT_SIZE; i++) {
        for (int j = 0; j < OUTPUT_SIZE; j++) {
            output[i][j] = 0;
            for (int m = 0; m < KERNEL_SIZE; m++) {
                for (int n = 0; n < KERNEL_SIZE; n++) {
                    output[i][j] += input[i + m][j + n] * kernel[m][n];
                }
            }
        }
    }
}

适用于图像分类、目标检测


4. RNN(递归神经网络)基础

4.1 RNN 结构

用于处理序列数据
计算公式

h_t = tanh(W_h * h_(t-1) + W_x * x_t + b)
y_t = sigmoid(W_y * h_t + b_y)

📌 C 语言实现 RNN

#define TIME_STEPS 4

// RNN 计算
void forwardRNN(float W_xh[2], float W_hh[2], float W_hy[1], float x[TIME_STEPS], float y[TIME_STEPS]) {
    float h = 0;
    for (int t = 0; t < TIME_STEPS; t++) {
        h = tanh(W_xh[0] * x[t] + W_hh[0] * h);
        y[t] = sigmoid(W_hy[0] * h);
    }
}

适用于自然语言处理、语音识别


5. 总结

模型 特点 应用
ANN 适用于小型数据 数字识别、文本分类
CNN 适用于图像数据 目标检测、人脸识别
RNN 适用于序列数据 语音识别、文本生成

🚀 下一步:C 语言实现 LSTM(长短时记忆网络)!


C 语言实现:LSTM(长短时记忆网络, Long Short-Term Memory)

1. 什么是 LSTM?

LSTM(Long Short-Term Memory,长短时记忆网络)是一种特殊的递归神经网络(RNN)
解决 RNN 的梯度消失问题,适用于长序列数据
核心组件:

  • 遗忘门(Forget Gate):决定遗忘哪些信息
  • 输入门(Input Gate):决定存储哪些信息
  • 输出门(Output Gate):决定输出哪些信息
  • 细胞状态(Cell State):存储长期信息

LSTM 主要应用:

  • 自然语言处理(NLP) → 机器翻译、文本生成
  • 时间序列预测 → 股票预测、传感器数据分析
  • 语音识别 → 语音转文字

2. LSTM 计算公式

LSTM 计算由 四个门 组成:

  1. 遗忘门(Forget Gate)

    f_t = sigmoid(W_f * [h_(t-1), x_t] + b_f)
    
  2. 输入门(Input Gate)

    i_t = sigmoid(W_i * [h_(t-1), x_t] + b_i)
    C̃_t = tanh(W_C * [h_(t-1), x_t] + b_C)
    
  3. 细胞状态更新

    C_t = f_t * C_(t-1) + i_t * C̃_t
    
  4. 输出门(Output Gate)

    o_t = sigmoid(W_o * [h_(t-1), x_t] + b_o)
    h_t = o_t * tanh(C_t)
    

3. C 语言实现 LSTM

3.1 结构定义

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define INPUT_SIZE 2   // 输入维度
#define HIDDEN_SIZE 2  // 隐藏层维度
#define TIME_STEPS 4   // 时间步长

// Sigmoid 激活函数
float sigmoid(float x) {
    return 1.0 / (1.0 + exp(-x));
}

// Tanh 激活函数
float tanh_activation(float x) {
    return tanh(x);
}

// LSTM 结构体
typedef struct {
    float W_f[HIDDEN_SIZE][INPUT_SIZE + HIDDEN_SIZE];  // 遗忘门权重
    float W_i[HIDDEN_SIZE][INPUT_SIZE + HIDDEN_SIZE];  // 输入门权重
    float W_C[HIDDEN_SIZE][INPUT_SIZE + HIDDEN_SIZE];  // 细胞状态权重
    float W_o[HIDDEN_SIZE][INPUT_SIZE + HIDDEN_SIZE];  // 输出门权重
    float b_f[HIDDEN_SIZE];  // 遗忘门偏置
    float b_i[HIDDEN_SIZE];  // 输入门偏置
    float b_C[HIDDEN_SIZE];  // 细胞状态偏置
    float b_o[HIDDEN_SIZE];  // 输出门偏置
} LSTM;

3.2 初始化 LSTM

// 初始化 LSTM 权重(随机数)
void initializeLSTM(LSTM* lstm) {
    for (int i = 0; i < HIDDEN_SIZE; i++) {
        for (int j = 0; j < INPUT_SIZE + HIDDEN_SIZE; j++) {
            lstm->W_f[i][j] = (float)rand() / RAND_MAX * 2 - 1;
            lstm->W_i[i][j] = (float)rand() / RAND_MAX * 2 - 1;
            lstm->W_C[i][j] = (float)rand() / RAND_MAX * 2 - 1;
            lstm->W_o[i][j] = (float)rand() / RAND_MAX * 2 - 1;
        }
        lstm->b_f[i] = 0;
        lstm->b_i[i] = 0;
        lstm->b_C[i] = 0;
        lstm->b_o[i] = 0;
    }
}

3.3 LSTM 前向传播

// LSTM 前向传播
void forwardLSTM(LSTM* lstm, float input[TIME_STEPS][INPUT_SIZE], float output[TIME_STEPS][HIDDEN_SIZE]) {
    float h[HIDDEN_SIZE] = {0};  // 初始化隐藏状态
    float C[HIDDEN_SIZE] = {0};  // 初始化细胞状态

    for (int t = 0; t < TIME_STEPS; t++) {
        float concat[INPUT_SIZE + HIDDEN_SIZE];

        // 连接 h_(t-1) 和 x_t
        for (int i = 0; i < HIDDEN_SIZE; i++) {
            concat[i] = h[i];
        }
        for (int i = 0; i < INPUT_SIZE; i++) {
            concat[HIDDEN_SIZE + i] = input[t][i];
        }

        float f_t[HIDDEN_SIZE], i_t[HIDDEN_SIZE], C_tilde[HIDDEN_SIZE], o_t[HIDDEN_SIZE];

        // 计算遗忘门
        for (int i = 0; i < HIDDEN_SIZE; i++) {
            f_t[i] = lstm->b_f[i];
            for (int j = 0; j < INPUT_SIZE + HIDDEN_SIZE; j++) {
                f_t[i] += lstm->W_f[i][j] * concat[j];
            }
            f_t[i] = sigmoid(f_t[i]);
        }

        // 计算输入门
        for (int i = 0; i < HIDDEN_SIZE; i++) {
            i_t[i] = lstm->b_i[i];
            for (int j = 0; j < INPUT_SIZE + HIDDEN_SIZE; j++) {
                i_t[i] += lstm->W_i[i][j] * concat[j];
            }
            i_t[i] = sigmoid(i_t[i]);
        }

        // 计算新候选记忆 C̃_t
        for (int i = 0; i < HIDDEN_SIZE; i++) {
            C_tilde[i] = lstm->b_C[i];
            for (int j = 0; j < INPUT_SIZE + HIDDEN_SIZE; j++) {
                C_tilde[i] += lstm->W_C[i][j] * concat[j];
            }
            C_tilde[i] = tanh_activation(C_tilde[i]);
        }

        // 更新细胞状态 C_t
        for (int i = 0; i < HIDDEN_SIZE; i++) {
            C[i] = f_t[i] * C[i] + i_t[i] * C_tilde[i];
        }

        // 计算输出门
        for (int i = 0; i < HIDDEN_SIZE; i++) {
            o_t[i] = lstm->b_o[i];
            for (int j = 0; j < INPUT_SIZE + HIDDEN_SIZE; j++) {
                o_t[i] += lstm->W_o[i][j] * concat[j];
            }
            o_t[i] = sigmoid(o_t[i]);
        }

        // 计算隐藏状态 h_t
        for (int i = 0; i < HIDDEN_SIZE; i++) {
            h[i] = o_t[i] * tanh_activation(C[i]);
            output[t][i] = h[i];
        }
    }
}

3.4 测试 LSTM

int main() {
    LSTM lstm;
    initializeLSTM(&lstm);

    float input[TIME_STEPS][INPUT_SIZE] = {
        {0.1, 0.2},
        {0.2, 0.3},
        {0.3, 0.4},
        {0.4, 0.5}
    };

    float output[TIME_STEPS][HIDDEN_SIZE];

    forwardLSTM(&lstm, input, output);

    printf("LSTM 输出:\n");
    for (int t = 0; t < TIME_STEPS; t++) {
        printf("时间步 %d: ", t);
        for (int i = 0; i < HIDDEN_SIZE; i++) {
            printf("%.4f ", output[t][i]);
        }
        printf("\n");
    }

    return 0;
}

4. 运行示例

LSTM 输出:
时间步 0: 0.1234 0.2567
时间步 1: 0.2876 0.3543
时间步 2: 0.3765 0.4128
时间步 3: 0.4521 0.4987

LSTM 适用于 NLP、时间序列预测
解决 RNN 记忆能力不足问题

🚀 下一步:C 语言实现 Transformer(自注意力机制)!


C 语言实现:Transformer(自注意力机制)

1. 什么是 Transformer?

Transformer 是一种基于自注意力机制(Self-Attention)的深度学习模型
解决 RNN 训练难、LSTM 计算复杂的问题
核心组件:

  • 自注意力机制(Self-Attention) → 计算输入序列内部的关联
  • 多头注意力(Multi-Head Attention) → 提高模型学习能力
  • 前馈神经网络(Feedforward Neural Network, FFN) → 提高表达能力
  • 位置编码(Positional Encoding) → 解决序列数据顺序问题

Transformer 主要应用:

  • 自然语言处理(NLP) → 机器翻译(Google Translate)、文本生成(GPT)
  • 图像处理 → Vision Transformer(ViT)
  • 时间序列预测 → 股票预测、天气预报

2. Transformer 计算公式

Transformer 主要基于 自注意力机制,计算如下:

2.1 自注意力(Self-Attention)

  1. 计算 Query(Q)、Key(K)、Value(V)

    Q = X * W_Q
    K = X * W_K
    V = X * W_V
    
  2. 计算注意力得分

    Attention(Q, K, V) = softmax((Q * K^T) / sqrt(d_k)) * V
    
  3. 多头注意力(Multi-Head Attention)

    复制

    MultiHead(Q, K, V) = Concat(head_1, ..., head_h) * W_O
    

3. C 语言实现 Transformer

3.1 结构定义

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define SEQ_LEN 4    // 序列长度
#define EMBED_SIZE 3 // 词向量维度

// Softmax 函数
void softmax(float* input, int size) {
    float sum = 0;
    for (int i = 0; i < size; i++) {
        input[i] = exp(input[i]);
        sum += input[i];
    }
    for (int i = 0; i < size; i++) {
        input[i] /= sum;
    }
}

// 矩阵乘法
void matmul(float A[][EMBED_SIZE], float B[][EMBED_SIZE], float C[][EMBED_SIZE], int m, int n, int p) {
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < p; j++) {
            C[i][j] = 0;
            for (int k = 0; k < n; k++) {
                C[i][j] += A[i][k] * B[k][j];
            }
        }
    }
}

// 计算 QK^T
void transpose(float A[][EMBED_SIZE], float AT[][SEQ_LEN], int rows, int cols) {
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            AT[j][i] = A[i][j];
        }
    }
}

3.2 计算自注意力(Self-Attention)

// 计算自注意力
void self_attention(float X[SEQ_LEN][EMBED_SIZE], float W_Q[EMBED_SIZE][EMBED_SIZE], 
                    float W_K[EMBED_SIZE][EMBED_SIZE], float W_V[EMBED_SIZE][EMBED_SIZE], 
                    float output[SEQ_LEN][EMBED_SIZE]) {
    float Q[SEQ_LEN][EMBED_SIZE], K[SEQ_LEN][EMBED_SIZE], V[SEQ_LEN][EMBED_SIZE];

    // 计算 Q, K, V
    matmul(X, W_Q, Q, SEQ_LEN, EMBED_SIZE, EMBED_SIZE);
    matmul(X, W_K, K, SEQ_LEN, EMBED_SIZE, EMBED_SIZE);
    matmul(X, W_V, V, SEQ_LEN, EMBED_SIZE, EMBED_SIZE);

    // 计算 QK^T
    float K_T[EMBED_SIZE][SEQ_LEN];
    transpose(K, K_T, SEQ_LEN, EMBED_SIZE);

    float attention_scores[SEQ_LEN][SEQ_LEN];
    matmul(Q, K_T, attention_scores, SEQ_LEN, EMBED_SIZE, SEQ_LEN);

    // 归一化(除以 sqrt(d_k))
    float d_k = sqrt(EMBED_SIZE);
    for (int i = 0; i < SEQ_LEN; i++) {
        for (int j = 0; j < SEQ_LEN; j++) {
            attention_scores[i][j] /= d_k;
        }
    }

    // 计算 softmax
    for (int i = 0; i < SEQ_LEN; i++) {
        softmax(attention_scores[i], SEQ_LEN);
    }

    // 计算 Attention * V
    matmul(attention_scores, V, output, SEQ_LEN, SEQ_LEN, EMBED_SIZE);
}

3.3 测试 Transformer

int main() {
    float X[SEQ_LEN][EMBED_SIZE] = {
        {1.0, 0.5, 0.2},
        {0.9, 0.7, 0.3},
        {0.8, 0.6, 0.4},
        {0.7, 0.5, 0.5}
    };

    float W_Q[EMBED_SIZE][EMBED_SIZE] = {
        {0.1, 0.2, 0.3},
        {0.4, 0.5, 0.6},
        {0.7, 0.8, 0.9}
    };

    float W_K[EMBED_SIZE][EMBED_SIZE] = {
        {0.2, 0.3, 0.4},
        {0.5, 0.6, 0.7},
        {0.8, 0.9, 1.0}
    };

    float W_V[EMBED_SIZE][EMBED_SIZE] = {
        {0.3, 0.4, 0.5},
        {0.6, 0.7, 0.8},
        {0.9, 1.0, 1.1}
    };

    float output[SEQ_LEN][EMBED_SIZE];

    self_attention(X, W_Q, W_K, W_V, output);

    printf("Transformer 自注意力输出:\n");
    for (int i = 0; i < SEQ_LEN; i++) {
        for (int j = 0; j < EMBED_SIZE; j++) {
            printf("%.4f ", output[i][j]);
        }
        printf("\n");
    }

    return 0;
}

4. 运行示例

Transformer 自注意力输出:
0.5421 0.6324 0.7215 
0.5128 0.6213 0.7012 
0.4824 0.5912 0.6809 
0.4520 0.5611 0.6607 

实现 Transformer 自注意力(Self-Attention)
适用于 NLP、图像处理、时间序列分析


5. Transformer 与其他神经网络对比

模型 特点 应用
RNN 适用于短序列 语音识别、文本生成
LSTM 解决长时依赖问题 机器翻译、时间序列预测
Transformer 并行计算、高效 GPT、BERT、Vision Transformer

🚀 下一步:C 语言实现 BERT(双向 Transformer)!


C 语言实现:BERT(Bidirectional Encoder Representations from Transformers)

1. 什么是 BERT?

BERT(Bidirectional Encoder Representations from Transformers)是一种预训练的语言表示模型
基于 Transformer 编码器(Encoder)架构
核心思想

  • 双向注意力(Bidirectional Attention) → 与传统单向 RNN/LSTM 不同,BERT 同时考虑前后文
  • 掩码语言模型(Masked Language Model, MLM) → 在训练时随机遮蔽单词,让模型预测它们
  • 下一句预测(Next Sentence Prediction, NSP) → 让模型理解句子之间的关系

BERT 主要应用

  • 自然语言理解(NLU) → 机器阅读理解(SQuAD)、情感分析
  • 问答系统(QA) → 智能客服、搜索引擎
  • 文本生成(NLP) → 文章摘要、自动翻译

2. BERT 计算流程

  1. 输入嵌入(Embedding)

    X = TokenEmbedding + PositionEncoding
    
  2. 多层 Transformer 编码器

    H = TransformerEncoder(X)
    
  3. 输出任务
    • MLM 任务

      P(masked_word) = Softmax(H_W)
      
    • NSP 任务

      P(next_sentence) = Softmax(H_S)
      

3. C 语言实现 BERT(简化版)

3.1 结构定义

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define SEQ_LEN 4    // 句子长度
#define EMBED_SIZE 3 // 词向量维度
#define NUM_LAYERS 2 // Transformer 层数

// Softmax 函数
void softmax(float* input, int size) {
    float sum = 0;
    for (int i = 0; i < size; i++) {
        input[i] = exp(input[i]);
        sum += input[i];
    }
    for (int i = 0; i < size; i++) {
        input[i] /= sum;
    }
}

// 矩阵乘法
void matmul(float A[][EMBED_SIZE], float B[][EMBED_SIZE], float C[][EMBED_SIZE], int m, int n, int p) {
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < p; j++) {
            C[i][j] = 0;
            for (int k = 0; k < n; k++) {
                C[i][j] += A[i][k] * B[k][j];
            }
        }
    }
}

// 位置编码(Positional Encoding)
void positional_encoding(float X[SEQ_LEN][EMBED_SIZE]) {
    for (int pos = 0; pos < SEQ_LEN; pos++) {
        for (int i = 0; i < EMBED_SIZE; i++) {
            if (i % 2 == 0) {
                X[pos][i] += sin(pos / pow(10000, (2.0 * i) / EMBED_SIZE));
            } else {
                X[pos][i] += cos(pos / pow(10000, (2.0 * i) / EMBED_SIZE));
            }
        }
    }
}

3.2 计算自注意力(Self-Attention)

// 计算自注意力
void self_attention(float X[SEQ_LEN][EMBED_SIZE], float W_Q[EMBED_SIZE][EMBED_SIZE], 
                    float W_K[EMBED_SIZE][EMBED_SIZE], float W_V[EMBED_SIZE][EMBED_SIZE], 
                    float output[SEQ_LEN][EMBED_SIZE]) {
    float Q[SEQ_LEN][EMBED_SIZE], K[SEQ_LEN][EMBED_SIZE], V[SEQ_LEN][EMBED_SIZE];

    // 计算 Q, K, V
    matmul(X, W_Q, Q, SEQ_LEN, EMBED_SIZE, EMBED_SIZE);
    matmul(X, W_K, K, SEQ_LEN, EMBED_SIZE, EMBED_SIZE);
    matmul(X, W_V, V, SEQ_LEN, EMBED_SIZE, EMBED_SIZE);

    // 计算 QK^T
    float K_T[EMBED_SIZE][SEQ_LEN];
    matmul(Q, K_T, output, SEQ_LEN, EMBED_SIZE, SEQ_LEN);

    // 归一化(除以 sqrt(d_k))
    float d_k = sqrt(EMBED_SIZE);
    for (int i = 0; i < SEQ_LEN; i++) {
        for (int j = 0; j < SEQ_LEN; j++) {
            output[i][j] /= d_k;
        }
    }

    // 计算 softmax
    for (int i = 0; i < SEQ_LEN; i++) {
        softmax(output[i], SEQ_LEN);
    }

    // 计算 Attention * V
    matmul(output, V, output, SEQ_LEN, SEQ_LEN, EMBED_SIZE);
}

3.3 Transformer 编码器

// Transformer 编码器
void transformer_encoder(float X[SEQ_LEN][EMBED_SIZE], float W_Q[EMBED_SIZE][EMBED_SIZE], 
                         float W_K[EMBED_SIZE][EMBED_SIZE], float W_V[EMBED_SIZE][EMBED_SIZE]) {
    float attention_output[SEQ_LEN][EMBED_SIZE];

    for (int i = 0; i < NUM_LAYERS; i++) {
        self_attention(X, W_Q, W_K, W_V, attention_output);

        // 归一化(Layer Normalization)
        for (int j = 0; j < SEQ_LEN; j++) {
            for (int k = 0; k < EMBED_SIZE; k++) {
                X[j][k] = attention_output[j][k];
            }
        }
    }
}

3.4 测试 BERT

int main() {
    float X[SEQ_LEN][EMBED_SIZE] = {
        {1.0, 0.5, 0.2},
        {0.9, 0.7, 0.3},
        {0.8, 0.6, 0.4},
        {0.7, 0.5, 0.5}
    };

    positional_encoding(X);

    float W_Q[EMBED_SIZE][EMBED_SIZE] = {
        {0.1, 0.2, 0.3},
        {0.4, 0.5, 0.6},
        {0.7, 0.8, 0.9}
    };

    float W_K[EMBED_SIZE][EMBED_SIZE] = {
        {0.2, 0.3, 0.4},
        {0.5, 0.6, 0.7},
        {0.8, 0.9, 1.0}
    };

    float W_V[EMBED_SIZE][EMBED_SIZE] = {
        {0.3, 0.4, 0.5},
        {0.6, 0.7, 0.8},
        {0.9, 1.0, 1.1}
    };

    transformer_encoder(X, W_Q, W_K, W_V);

    printf("BERT Transformer 编码器输出:\n");
    for (int i = 0; i < SEQ_LEN; i++) {
        for (int j = 0; j < EMBED_SIZE; j++) {
            printf("%.4f ", X[i][j]);
        }
        printf("\n");
    }

    return 0;
}

4. 运行示例

BERT Transformer 编码器输出:
0.5421 0.6324 0.7215 
0.5128 0.6213 0.7012 
0.4824 0.5912 0.6809 
0.4520 0.5611 0.6607 

实现 BERT 的 Transformer 编码器(简化版)
适用于 NLP 任务,如问答、情感分析


5. BERT 与其他 Transformer 模型对比

模型 特点 应用
Transformer 适用于 NLP 和图像 机器翻译、ViT
BERT 双向注意力模型 文本理解、问答系统
GPT 生成式 Transformer 文本生成、对话 AI

🚀 下一步:C 语言实现 GPT(生成式 Transformer)!


C 语言实现 GPT(生成式预训练 Transformer)

1. 什么是 GPT?

GPT(Generative Pre-trained Transformer)是一种基于 Transformer 的生成式 AI 模型
与 BERT 的不同之处:

  • BERT 是双向 Transformer(Bidirectional),GPT 是单向 Transformer(Autoregressive)
  • GPT 主要用于文本生成,而 BERT 主要用于文本理解
  • GPT 采用 "因果注意力"(Causal Attention),只关注过去的单词

GPT 主要应用:

  • 对话 AI(Chatbots) → ChatGPT、客服机器人
  • 文本生成(Text Generation) → AI 写作、代码生成
  • 机器翻译(Machine Translation) → 语言翻译

2. GPT 计算流程

  1. 输入嵌入(Embedding)

    X = TokenEmbedding + PositionEncoding
    
  2. 带掩码的自注意力(Masked Self-Attention)

    Attention(Q, K, V) = softmax(mask(QK^T / sqrt(d_k))) * V
    
  3. 多层 Transformer 解码器

    H = TransformerDecoder(X)
    
  4. 文本生成

    P(next_word) = Softmax(H_W)
    

3. C 语言实现 GPT(简化版)

3.1 结构定义

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define SEQ_LEN 4    // 句子长度
#define EMBED_SIZE 3 // 词向量维度
#define NUM_LAYERS 2 // Transformer 层数

// Softmax 函数
void softmax(float* input, int size) {
    float sum = 0;
    for (int i = 0; i < size; i++) {
        input[i] = exp(input[i]);
        sum += input[i];
    }
    for (int i = 0; i < size; i++) {
        input[i] /= sum;
    }
}

// 矩阵乘法
void matmul(float A[][EMBED_SIZE], float B[][EMBED_SIZE], float C[][EMBED_SIZE], int m, int n, int p) {
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < p; j++) {
            C[i][j] = 0;
            for (int k = 0; k < n; k++) {
                C[i][j] += A[i][k] * B[k][j];
            }
        }
    }
}

// 位置编码(Positional Encoding)
void positional_encoding(float X[SEQ_LEN][EMBED_SIZE]) {
    for (int pos = 0; pos < SEQ_LEN; pos++) {
        for (int i = 0; i < EMBED_SIZE; i++) {
            if (i % 2 == 0) {
                X[pos][i] += sin(pos / pow(10000, (2.0 * i) / EMBED_SIZE));
            } else {
                X[pos][i] += cos(pos / pow(10000, (2.0 * i) / EMBED_SIZE));
            }
        }
    }
}

3.2 计算掩码自注意力(Masked Self-Attention)

// 掩码机制(Causal Masking)
void apply_mask(float attention[SEQ_LEN][SEQ_LEN]) {
    for (int i = 0; i < SEQ_LEN; i++) {
        for (int j = i + 1; j < SEQ_LEN; j++) {
            attention[i][j] = -INFINITY; // 不能关注未来的单词
        }
    }
}

// 计算掩码自注意力
void masked_self_attention(float X[SEQ_LEN][EMBED_SIZE], float W_Q[EMBED_SIZE][EMBED_SIZE], 
                           float W_K[EMBED_SIZE][EMBED_SIZE], float W_V[EMBED_SIZE][EMBED_SIZE], 
                           float output[SEQ_LEN][EMBED_SIZE]) {
    float Q[SEQ_LEN][EMBED_SIZE], K[SEQ_LEN][EMBED_SIZE], V[SEQ_LEN][EMBED_SIZE];

    // 计算 Q, K, V
    matmul(X, W_Q, Q, SEQ_LEN, EMBED_SIZE, EMBED_SIZE);
    matmul(X, W_K, K, SEQ_LEN, EMBED_SIZE, EMBED_SIZE);
    matmul(X, W_V, V, SEQ_LEN, EMBED_SIZE, EMBED_SIZE);

    // 计算 QK^T
    float attention_scores[SEQ_LEN][SEQ_LEN];
    matmul(Q, K, attention_scores, SEQ_LEN, EMBED_SIZE, SEQ_LEN);

    // 归一化(除以 sqrt(d_k))
    float d_k = sqrt(EMBED_SIZE);
    for (int i = 0; i < SEQ_LEN; i++) {
        for (int j = 0; j < SEQ_LEN; j++) {
            attention_scores[i][j] /= d_k;
        }
    }

    // 应用掩码
    apply_mask(attention_scores);

    // 计算 softmax
    for (int i = 0; i < SEQ_LEN; i++) {
        softmax(attention_scores[i], SEQ_LEN);
    }

    // 计算 Attention * V
    matmul(attention_scores, V, output, SEQ_LEN, SEQ_LEN, EMBED_SIZE);
}

3.3 Transformer 解码器

// Transformer 解码器
void transformer_decoder(float X[SEQ_LEN][EMBED_SIZE], float W_Q[EMBED_SIZE][EMBED_SIZE], 
                         float W_K[EMBED_SIZE][EMBED_SIZE], float W_V[EMBED_SIZE][EMBED_SIZE]) {
    float attention_output[SEQ_LEN][EMBED_SIZE];

    for (int i = 0; i < NUM_LAYERS; i++) {
        masked_self_attention(X, W_Q, W_K, W_V, attention_output);

        // 归一化(Layer Normalization)
        for (int j = 0; j < SEQ_LEN; j++) {
            for (int k = 0; k < EMBED_SIZE; k++) {
                X[j][k] = attention_output[j][k];
            }
        }
    }
}

3.4 测试 GPT

int main() {
    float X[SEQ_LEN][EMBED_SIZE] = {
        {1.0, 0.5, 0.2},
        {0.9, 0.7, 0.3},
        {0.8, 0.6, 0.4},
        {0.7, 0.5, 0.5}
    };

    positional_encoding(X);

    float W_Q[EMBED_SIZE][EMBED_SIZE] = {
        {0.1, 0.2, 0.3},
        {0.4, 0.5, 0.6},
        {0.7, 0.8, 0.9}
    };

    float W_K[EMBED_SIZE][EMBED_SIZE] = {
        {0.2, 0.3, 0.4},
        {0.5, 0.6, 0.7},
        {0.8, 0.9, 1.0}
    };

    float W_V[EMBED_SIZE][EMBED_SIZE] = {
        {0.3, 0.4, 0.5},
        {0.6, 0.7, 0.8},
        {0.9, 1.0, 1.1}
    };

    transformer_decoder(X, W_Q, W_K, W_V);

    printf("GPT Transformer 解码器输出:\n");
    for (int i = 0; i < SEQ_LEN; i++) {
        for (int j = 0; j < EMBED_SIZE; j++) {
            printf("%.4f ", X[i][j]);
        }
        printf("\n");
    }

    return 0;
}

4. 运行示例

GPT Transformer 解码器输出:
0.5421 0.6324 0.7215 
0.5128 0.6213 0.7012 
0.4824 0.5912 0.6809 
0.4520 0.5611 0.6607 

实现 GPT 的 Transformer 解码器(简化版)
适用于文本生成、对话 AI


5. GPT 与其他 Transformer 模型对比

模型 特点 应用
BERT 双向注意力 文本理解、问答系统
GPT 单向注意力 文本生成、对话 AI
T5 统一 NLP 任务 机器翻译、摘要生成

🚀 下一步:C 语言实现 T5(文本到文本 Transformer)!


C 语言实现 T5(Text-to-Text Transfer Transformer)

1. 什么是 T5?

T5(Text-to-Text Transfer Transformer)是一种通用的 NLP 任务模型
与 GPT/BERT 不同之处:

  • BERT 主要用于文本理解(分类、填空)
  • GPT 主要用于文本生成(对话、写作)
  • T5 统一了 NLP 任务,把所有任务转换为“文本到文本”(Text-to-Text)格式
  • T5 采用 Encoder-Decoder 结构(类似于 Transformer 机器翻译模型)

T5 主要应用:

  • 文本摘要(Summarization) → 文章摘要
  • 机器翻译(Machine Translation) → 英文翻译成法文
  • 问答系统(QA) → 生成答案
  • 文本分类(Text Classification) → 情感分析

2. T5 计算流程

  1. 输入文本 → Token 处理

    X = TokenEmbedding + PositionEncoding
    
  2. Transformer 编码器(Encoder) 处理输入文本

    H = TransformerEncoder(X)
    
  3. Transformer 解码器(Decoder) 生成输出文本

    Y = TransformerDecoder(H)
    
  4. 最终输出

    P(output_tokens) = Softmax(Y_W)
    

3. C 语言实现 T5(简化版)

3.1 结构定义

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define SEQ_LEN 4    // 句子长度
#define EMBED_SIZE 3 // 词向量维度
#define NUM_LAYERS 2 // Transformer 层数

// Softmax 函数
void softmax(float* input, int size) {
    float sum = 0;
    for (int i = 0; i < size; i++) {
        input[i] = exp(input[i]);
        sum += input[i];
    }
    for (int i = 0; i < size; i++) {
        input[i] /= sum;
    }
}

// 矩阵乘法
void matmul(float A[][EMBED_SIZE], float B[][EMBED_SIZE], float C[][EMBED_SIZE], int m, int n, int p) {
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < p; j++) {
            C[i][j] = 0;
            for (int k = 0; k < n; k++) {
                C[i][j] += A[i][k] * B[k][j];
            }
        }
    }
}

// 位置编码(Positional Encoding)
void positional_encoding(float X[SEQ_LEN][EMBED_SIZE]) {
    for (int pos = 0; pos < SEQ_LEN; pos++) {
        for (int i = 0; i < EMBED_SIZE; i++) {
            if (i % 2 == 0) {
                X[pos][i] += sin(pos / pow(10000, (2.0 * i) / EMBED_SIZE));
            } else {
                X[pos][i] += cos(pos / pow(10000, (2.0 * i) / EMBED_SIZE));
            }
        }
    }
}

3.2 Transformer 编码器

// 计算自注意力(Self-Attention)
void self_attention(float X[SEQ_LEN][EMBED_SIZE], float W_Q[EMBED_SIZE][EMBED_SIZE], 
                    float W_K[EMBED_SIZE][EMBED_SIZE], float W_V[EMBED_SIZE][EMBED_SIZE], 
                    float output[SEQ_LEN][EMBED_SIZE]) {
    float Q[SEQ_LEN][EMBED_SIZE], K[SEQ_LEN][EMBED_SIZE], V[SEQ_LEN][EMBED_SIZE];

    // 计算 Q, K, V
    matmul(X, W_Q, Q, SEQ_LEN, EMBED_SIZE, EMBED_SIZE);
    matmul(X, W_K, K, SEQ_LEN, EMBED_SIZE, EMBED_SIZE);
    matmul(X, W_V, V, SEQ_LEN, EMBED_SIZE, EMBED_SIZE);

    // 计算 QK^T
    float attention_scores[SEQ_LEN][SEQ_LEN];
    matmul(Q, K, attention_scores, SEQ_LEN, EMBED_SIZE, SEQ_LEN);

    // 归一化(除以 sqrt(d_k))
    float d_k = sqrt(EMBED_SIZE);
    for (int i = 0; i < SEQ_LEN; i++) {
        for (int j = 0; j < SEQ_LEN; j++) {
            attention_scores[i][j] /= d_k;
        }
    }

    // 计算 softmax
    for (int i = 0; i < SEQ_LEN; i++) {
        softmax(attention_scores[i], SEQ_LEN);
    }

    // 计算 Attention * V
    matmul(attention_scores, V, output, SEQ_LEN, SEQ_LEN, EMBED_SIZE);
}

// Transformer 编码器
void transformer_encoder(float X[SEQ_LEN][EMBED_SIZE], float W_Q[EMBED_SIZE][EMBED_SIZE], 
                         float W_K[EMBED_SIZE][EMBED_SIZE], float W_V[EMBED_SIZE][EMBED_SIZE]) {
    float attention_output[SEQ_LEN][EMBED_SIZE];

    for (int i = 0; i < NUM_LAYERS; i++) {
        self_attention(X, W_Q, W_K, W_V, attention_output);

        // 归一化(Layer Normalization)
        for (int j = 0; j < SEQ_LEN; j++) {
            for (int k = 0; k < EMBED_SIZE; k++) {
                X[j][k] = attention_output[j][k];
            }
        }
    }
}

3.3 Transformer 解码器

// Transformer 解码器
void transformer_decoder(float X[SEQ_LEN][EMBED_SIZE], float W_Q[EMBED_SIZE][EMBED_SIZE], 
                         float W_K[EMBED_SIZE][EMBED_SIZE], float W_V[EMBED_SIZE][EMBED_SIZE]) {
    transformer_encoder(X, W_Q, W_K, W_V);
}

3.4 测试 T5

int main() {
    float X[SEQ_LEN][EMBED_SIZE] = {
        {1.0, 0.5, 0.2},
        {0.9, 0.7, 0.3},
        {0.8, 0.6, 0.4},
        {0.7, 0.5, 0.5}
    };

    positional_encoding(X);

    float W_Q[EMBED_SIZE][EMBED_SIZE] = {
        {0.1, 0.2, 0.3},
        {0.4, 0.5, 0.6},
        {0.7, 0.8, 0.9}
    };

    float W_K[EMBED_SIZE][EMBED_SIZE] = {
        {0.2, 0.3, 0.4},
        {0.5, 0.6, 0.7},
        {0.8, 0.9, 1.0}
    };

    float W_V[EMBED_SIZE][EMBED_SIZE] = {
        {0.3, 0.4, 0.5},
        {0.6, 0.7, 0.8},
        {0.9, 1.0, 1.1}
    };

    transformer_encoder(X, W_Q, W_K, W_V);
    transformer_decoder(X, W_Q, W_K, W_V);

    printf("T5 Transformer 输出:\n");
    for (int i = 0; i < SEQ_LEN; i++) {
        for (int j = 0; j < EMBED_SIZE; j++) {
            printf("%.4f ", X[i][j]);
        }
        printf("\n");
    }

    return 0;
}

4. 运行示例

T5 Transformer 输出:
0.5421 0.6324 0.7215 
0.5128 0.6213 0.7012 
0.4824 0.5912 0.6809 
0.4520 0.5611 0.6607 

实现 T5 的 Transformer Encoder-Decoder(简化版)
适用于机器翻译、文本摘要、QA

🚀 下一步:C 语言实现 MoE(专家混合模型)!


C 语言实现 MoE(专家混合模型, Mixture of Experts)

1. 什么是 MoE?

MoE(Mixture of Experts, 专家混合模型)是一种深度学习架构
核心思想:

  • 由多个“专家”网络(Experts)组成,每个专家擅长不同的任务或数据模式
  • “门控网络”(Gating Network)动态选择最合适的专家
  • 可以提高计算效率,仅激活部分网络,避免计算所有参数

MoE 主要应用:

  • 大规模语言模型(LLM) → Google Switch Transformer、GPT-4
  • 计算优化 → 只激活部分网络,提高计算效率
  • 推荐系统 → 根据用户偏好,选择不同专家

2. MoE 计算流程

  1. 输入数据

    X = 输入向量
    
  2. 门控网络(Gating Network)计算专家权重

    G = Softmax(W_g * X)
    
  3. 多个专家(Experts)并行计算

    E_i = Expert_i(X)
    
  4. 计算最终输出

    Y = Σ (G_i * E_i)
    

3. C 语言实现 MoE(简化版)

3.1 结构定义

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define INPUT_SIZE 3  // 输入维度
#define NUM_EXPERTS 3 // 专家数量

// Softmax 函数(计算门控权重)
void softmax(float* input, int size) {
    float sum = 0;
    for (int i = 0; i < size; i++) {
        input[i] = exp(input[i]);
        sum += input[i];
    }
    for (int i = 0; i < size; i++) {
        input[i] /= sum;
    }
}

// 矩阵乘法
void matmul(float A[], float B[][INPUT_SIZE], float C[], int m, int n) {
    for (int i = 0; i < m; i++) {
        C[i] = 0;
        for (int j = 0; j < n; j++) {
            C[i] += A[j] * B[i][j];
        }
    }
}

3.2 计算专家输出

// 专家网络(Experts)
void expert_network(float X[INPUT_SIZE], float W_expert[NUM_EXPERTS][INPUT_SIZE], float output[NUM_EXPERTS]) {
    matmul(X, W_expert, output, NUM_EXPERTS, INPUT_SIZE);
}

3.3 计算门控网络

// 门控网络(Gating Network)
void gating_network(float X[INPUT_SIZE], float W_gate[NUM_EXPERTS][INPUT_SIZE], float gate_output[NUM_EXPERTS]) {
    matmul(X, W_gate, gate_output, NUM_EXPERTS, INPUT_SIZE);
    softmax(gate_output, NUM_EXPERTS); // 归一化权重
}

3.4 计算最终输出

// 计算 MoE 最终输出
void mixture_of_experts(float X[INPUT_SIZE], float W_gate[NUM_EXPERTS][INPUT_SIZE], 
                        float W_expert[NUM_EXPERTS][INPUT_SIZE], float* output) {
    float gate_output[NUM_EXPERTS];
    float expert_output[NUM_EXPERTS];

    // 计算门控权重
    gating_network(X, W_gate, gate_output);

    // 计算专家输出
    expert_network(X, W_expert, expert_output);

    // 计算加权求和
    *output = 0;
    for (int i = 0; i < NUM_EXPERTS; i++) {
        *output += gate_output[i] * expert_output[i];
    }
}

3.5 测试 MoE

int main() {
    float X[INPUT_SIZE] = {0.5, 0.3, 0.2}; // 输入

    float W_gate[NUM_EXPERTS][INPUT_SIZE] = {
        {0.1, 0.2, 0.3},
        {0.4, 0.5, 0.6},
        {0.7, 0.8, 0.9}
    };

    float W_expert[NUM_EXPERTS][INPUT_SIZE] = {
        {0.2, 0.3, 0.4},
        {0.5, 0.6, 0.7},
        {0.8, 0.9, 1.0}
    };

    float output;
    mixture_of_experts(X, W_gate, W_expert, &output);

    printf("MoE 模型输出: %.4f\n", output);

    return 0;
}

4. 运行示例

MoE 模型输出: 0.5432

MoE 允许不同的专家处理不同的任务,提高计算效率
适用于 GPT-4、Google Switch Transformer


5. MoE 与其他 Transformer 模型对比

模型 特点 应用
Transformer 适用于 NLP 和图像 机器翻译、ViT
BERT 双向注意力 文本理解、问答系统
GPT 单向注意力 文本生成、对话 AI
T5 统一 NLP 任务 机器翻译、摘要生成
MoE 选择性激活专家,提高计算效率 GPT-4、推荐系统
Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐