C#构建一个简单的循环神经网络,模拟对话
循环神经网络(Recurrent Neural Network, RNN)是一种用于处理序列数据的神经网络模型。与传统的前馈神经网络不同,RNN具有内部记忆能力,可以捕捉到序列中元素之间的依赖关系。这种特性使得RNN在自然语言处理、语音识别、时间序列预测等需要考虑上下文信息的任务中表现出色。
RNN的基本结构
RNN的基本结构包括输入层、隐藏层和输出层。在处理序列数据时,RNN会按照序列的时间顺序逐个处理每个元素。对于序列中的每一个时间步,RNN不仅会接收该时间步的输入,还会接收上一个时间步的隐藏状态作为输入。这样,通过将之前的信息传递给后续的处理步骤,RNN能够利用历史信息来影响当前的输出。
方法
InitializeWeightsAndBiases():使用随机值初始化权重矩阵和偏置向量。Sigmoid():激活函数,用于隐藏层的非线性变换。RandomMatrix():生成指定大小的随机矩阵,用于权重的初始化。Softmax():通常用于多分类问题中的输出层,将输出转换为概率分布。Forward():前向传播方法,根据输入数据计算每个时间步的输出。它会更新隐藏状态,并最终返回所有时间步的输出列表。Backward():反向传播方法,用于根据预测输出与目标输出之间的差异调整模型参数。它计算梯度并更新权重和偏置。UpdateWeights():根据计算出的梯度更新模型的权重和偏置。Train():训练模型的方法,通过多次迭代(epoch)对输入数据进行前向传播和反向传播,以优化模型参数。Predict():预测方法,根据输入数据返回每个时间步的预测结果索引,即输出概率最高的类别。
说明
这只是一个基础的 RNN 模型实现,实际应用中可能需要考虑更多的优化技术,比如使用长短期记忆网络(LSTM)、门控循环单元(GRU)等更复杂的架构来改善性能。
using System;
using System.Linq;
using System.Collections.Generic;namespace Project.NeuralNetwork
{/// <summary>/// 构建神经网络/// </summary>public class RnnModel{/// <summary>/// 输入层大小/// </summary>private readonly int _inputSize;/// <summary>/// 隐藏层大小/// </summary>private readonly int _hiddenSize;/// <summary>/// 输出层大小/// </summary>private readonly int _outputSize;/// <summary>/// 输入到隐藏层的权重/// </summary>private double[,] _weightsInputHidden;/// <summary>/// 隐藏层到隐藏层的权重/// </summary>private double[,] _weightsHiddenHidden;/// <summary>/// 隐藏层到输出层的权重/// </summary>private double[,] _weightsHiddenOutput;/// <summary>/// 隐藏层偏置/// </summary>private double[] _biasHidden;/// <summary>/// 输出层偏置/// </summary>private double[] _biasOutput;/// <summary>/// 隐藏层状态/// </summary>private double[] _hiddenState;/// <summary>/// 初始化模型的构造函数/// </summary>/// <param name="inputSize"></param>/// <param name="hiddenSize"></param>/// <param name="outputSize"></param>public RnnModel(int inputSize, int hiddenSize, int outputSize){_inputSize = inputSize;_hiddenSize = hiddenSize;_outputSize = outputSize;InitializeWeightsAndBiases();}/// <summary>/// 初始化权重和偏置/// </summary>private void InitializeWeightsAndBiases(){_weightsInputHidden = RandomMatrix(_inputSize, _hiddenSize);_weightsHiddenHidden = RandomMatrix(_hiddenSize, _hiddenSize);_weightsHiddenOutput = RandomMatrix(_hiddenSize, _outputSize);_biasHidden = new double[_hiddenSize];_biasOutput = new double[_outputSize];}/// <summary>/// 激活函数/// </summary>/// <param name="x"></param>/// <returns></returns>private double Sigmoid(double x){return 1 / (1 + Math.Exp(-x));}/// <summary>/// 生成随机矩阵/// </summary>/// <param name="rows"></param>/// <param name="cols"></param>/// <returns></returns>private double[,] RandomMatrix(int rows, int cols){var matrix = new double[rows, cols];var random = new Random();for (int i = 0; i < rows; i++){for (int j = 0; j < cols; j++){matrix[i, j] = random.NextDouble() * 2 - 1; // [-1, 1]}}return matrix;}/// <summary>/// 前向传播/// </summary>/// <param name="inputs"></param>/// <returns></returns>public List<double[]> Forward(List<double[]> inputs){_hiddenState = new double[_hiddenSize];var outputs = new List<double[]>();foreach (var input in inputs){var hidden = new double[_hiddenSize];for (int h = 0; h < _hiddenSize; h++){hidden[h] = _biasHidden[h];for (int i = 0; i < _inputSize; i++){hidden[h] += _weightsInputHidden[i, h] * input[i];}for (int hh = 0; hh < _hiddenSize; hh++){hidden[h] += _weightsHiddenHidden[hh, h] * _hiddenState[hh];}hidden[h] = Sigmoid(hidden[h]);}_hiddenState = hidden;var output = Output(hidden);outputs.Add(output);}return outputs;}/// <summary>/// 输出层/// </summary>/// <param name="h"></param>/// <returns></returns>private double[] Output(double[] h){double[] y = new double[_outputSize];for (int i = 0; i < _outputSize; i++){double sum = _biasOutput[i];for (int j = 0; j < _hiddenSize; j++){sum += h[j] * _weightsHiddenOutput[j, i];}y[i] = sum;}return Softmax(y);}/// <summary>/// 输出层的激活函数/// </summary>/// <param name="x"></param>/// <returns></returns>private double[] Softmax(double[] x){double max = x.Max();double expSum = x.Select(xi => Math.Exp(xi - max)).Sum();return x.Select(xi => Math.Exp(xi - max) / expSum).ToArray();}/// <summary>/// 反向传播/// </summary>/// <param name="inputs"></param>/// <param name="targets"></param>/// <param name="outputs"></param>/// <param name="learningRate"></param>private void Backward(List<double[]> inputs, List<double[]> targets, List<double[]> outputs, double learningRate){//输入到隐藏层的梯度double[,] dWeightsInputHidden = new double[_inputSize, _hiddenSize];//隐藏层到隐藏层的梯度double[,] dWeightsHiddenHidden = new double[_hiddenSize, _hiddenSize];//隐藏层到输出层的梯度double[,] dWeightsHiddenOutput = new double[_hiddenSize, _outputSize];//隐藏层的偏置double[] dBiasHidden = new double[_hiddenSize];//输出层的偏置double[] dBiasOutput = new double[_outputSize];for (int t = inputs.Count - 1; t >= 0; t--){double[] targetVector = new double[_outputSize];Array.Copy(targets[t], targetVector, _outputSize);// 计算输出层的误差for (int o = 0; o < _outputSize; o++){dBiasOutput[o] = outputs[t][o] - targetVector[o];}// 计算隐藏层到输出层的梯度for (int o = 0; o < _outputSize; o++){for (int h = 0; h < _hiddenSize; h++){dWeightsHiddenOutput[h, o] += dBiasOutput[o] * _hiddenState[h];}}// 计算隐藏层的偏置double[] dh = new double[_hiddenSize];for (int h = 0; h < _hiddenSize; h++){double error = 0;for (int o = 0; o < _outputSize; o++){error += dBiasOutput[o] * _weightsHiddenOutput[h, o];}dh[h] = error * (_hiddenState[h] * (1 - _hiddenState[h]));}for (int h = 0; h < _hiddenSize; h++){dBiasHidden[h] += dh[h];}//计算输入到隐藏层的梯度for (int h = 0; h < _hiddenSize; h++){for (int i = 0; i < _inputSize; i++){dWeightsInputHidden[i, h] += dh[h] * inputs[t][i];}}// 计算输入到隐藏层的梯度if (t > 0){for (int h = 0; h < _hiddenSize; h++){for (int hh = 0; hh < _hiddenSize; hh++){dWeightsHiddenHidden[hh, h] += dh[h] * _hiddenState[hh];}}}}// 更新权重和偏置UpdateWeights(dWeightsInputHidden, dWeightsHiddenHidden, dWeightsHiddenOutput, dBiasHidden, dBiasOutput, learningRate);}/// <summary>/// 更新权重/// </summary>/// <param name="dWxh"></param>/// <param name="dWhh"></param>/// <param name="dWhy"></param>/// <param name="dbh"></param>/// <param name="dby"></param>/// <param name="learningRate"></param>private void UpdateWeights(double[,] dWeightsInputHidden, double[,] dWeightsHiddenHidden, double[,] dWeightsHiddenOutput, double[] dBiasHidden, double[] dBiasOutput, double learningRate){// 更新输入到隐藏层的权重for (int i = 0; i < _inputSize; i++){for (int h = 0; h < _hiddenSize; h++){_weightsInputHidden[i, h] -= learningRate * dWeightsInputHidden[i, h];}}//更新隐藏层到隐藏层的权重for (int h = 0; h < _hiddenSize; h++){for (int hh = 0; hh < _hiddenSize; hh++){_weightsHiddenHidden[h, hh] -= learningRate * dWeightsHiddenHidden[h, hh];}}//更新隐藏层到输出层的权重for (int h = 0; h < _hiddenSize; h++){for (int o = 0; o < _outputSize; o++){_weightsHiddenOutput[h, o] -= learningRate * dWeightsHiddenOutput[h, o];}}//更新隐藏层的偏置for (int h = 0; h < _hiddenSize; h++){_biasHidden[h] -= learningRate * dBiasHidden[h];}//更新输出层的偏置for (int o = 0; o < _outputSize; o++){_biasOutput[o] -= learningRate * dBiasOutput[o];}}/// <summary>/// 训练/// </summary>/// <param name="inputs"></param>/// <param name="targets"></param>/// <param name="epochs"></param>/// <param name="learningRate"></param>public void Train(List<List<double[]>> inputs, List<List<double[]>> targets, double learningRate, int epochs){for (int epoch = 0; epoch < epochs; epoch++){for (int i = 0; i < inputs.Count; i++){List<double[]> input = inputs[i];List<double[]> target = targets[i];List<double[]> outputs = Forward(input);Backward(input, target, outputs, learningRate);}}}/// <summary>/// 预测/// </summary>/// <param name="inputs"></param>/// <returns></returns>public int[] Predict(List<double[]> inputs){var output = Forward(inputs);var predictedIndices = output.Select(o => Array.IndexOf(o, o.Max())).ToArray();return predictedIndices;}}
}
- 准备训练数据
- 训练网络
- 测试并输出结果
public static void Rnn_Predict()
{// 定义数据集var data = new List<Tuple<string[], string[]>>{Tuple.Create(new string[] { "早安" }, new string[] { "早上好" }),Tuple.Create(new string[] { "午安" }, new string[] { "中午好" }),Tuple.Create(new string[] { "晚安" }, new string[] { "晚上好" }),Tuple.Create(new string[] { "你好吗?" }, new string[] { "我很好,谢谢。" })};// 创建词汇表var allWords = data.SelectMany(t => t.Item1.Concat(t.Item2)).Distinct().ToList();var wordToIndex = allWords.ToDictionary(word => word, word => allWords.IndexOf(word));// 将字符串转换为one-hot编码List<List<double[]>> inputsData = new List<List<double[]>>();List<List<double[]>> targetsData = new List<List<double[]>>();foreach (var item in data){var inputSequence = item.Item1.Select(word => OneHotEncode(word, wordToIndex)).ToList();var targetSequence = item.Item2.Select(word => OneHotEncode(word, wordToIndex)).ToList();inputsData.Add(inputSequence);targetsData.Add(targetSequence);}double[] OneHotEncode(string word, Dictionary<string, int> wordToIndex){var encoding = new double[wordToIndex.Count];encoding[wordToIndex[word]] = 1;return encoding;}//开始训练int inputSize = allWords.Count;int hiddenSize = allWords.Count;int outputSize = allWords.Count;RnnModel model = new RnnModel(inputSize, hiddenSize, outputSize);int epochs = 10000;double learningRate = 0.1;model.Train(inputsData, targetsData, learningRate, epochs);//预测while (true){Console.Write("你: ");string userInput = Console.ReadLine();if (userInput.ToLower() == "exit"){break;}if (!allWords.Contains(userInput)){Console.WriteLine("对不起,我不认识这些词。");continue;}var testInput = new List<double[]> { OneHotEncode(userInput, wordToIndex) };var prediction = model.Predict(testInput);var predictedWords = prediction.Select(index => allWords[index]).ToArray();Console.WriteLine($"机器人: {string.Join(", ", predictedWords)}");}
}
相关文章:
C#构建一个简单的循环神经网络,模拟对话
循环神经网络(Recurrent Neural Network, RNN)是一种用于处理序列数据的神经网络模型。与传统的前馈神经网络不同,RNN具有内部记忆能力,可以捕捉到序列中元素之间的依赖关系。这种特性使得RNN在自然语言处理、语音识别、时间序列预…...
Linux上安装单机版Kibana6.8.1
1. 下载安装包 kibana-6.8.1-linux-x86_64.tar.gz 链接:https://pan.baidu.com/s/1b4kION9wFXIVHuWDn2J-Aw 提取码:rdrc 2. Kibana启动不能使用root用户,使用ES里创建的elsearch用户,进行赋权: chown -R elsearch:els…...
短视频矩阵矩阵,矩阵号策略
随着数字媒体的迅猛发展,短视频平台已经成为企业和个人品牌推广的核心渠道。在这一背景下,短视频矩阵营销策略应运而生,它通过高效整合和管理多个短视频账号,实现资源的最优配置和营销效果的最大化。本文旨在深入探讨短视频矩阵的…...
Rust 力扣 - 2266. 统计打字方案数
文章目录 题目描述题解思路题解代码题目链接 题目描述 题解思路 这题可以先求按了多少次相同连续的按钮,所有的连续相同按钮表示的方案数的乘积就是本题答案 我们的关键问题就转换成了按n个连续相同按钮表示的方案数 设f(i)表示按i个连续相同按钮表示的方案数 如…...
【大数据技术与开发实训】携程景点在线评论分析
景点在线评论分析 题目要求实验目标技术实现数据采集获取所有相关景点页面的 URL获取所有相关景点对应的 poiId 及其他有用信息通过 poiId 获取所有景点的全部评论数据采集结果 数据预处理景点信息的数据预处理查看数据基本信息缺失值处理 用户评论的数据处理缺失值处理分词、去…...
46.坑王驾到第十期:vscode 无法使用 tsc 命令
点赞收藏加关注,你也能住大别墅! 一、问题重现 上一篇帖子记录了我昨天在mac上安装typescript及调试的过程。今天打开vscode准备开干的时候,发现tsc命令又无法使用了,然后按照昨天的方法重新安装调试后又能用了,但是关…...
postman 调用 下载接口(download)使用默认名称(response.txt 或随机名称)
官网地址:https://www.postman.com 介绍 Postman 是一款流行的 API 开发和测试工具,用于发送 HTTP 请求、测试接口、调试服务器响应以及进行 API 文档管理。它支持多种请求类型(如 GET、POST、PUT、DELETE 等),并且功能…...
单片机_简单AI模型训练与部署__从0到0.9
IDE: CLion MCU: STM32F407VET6 一、导向 以求知为导向,从问题到寻求问题解决的方法,以兴趣驱动学习。 虽从0,但不到1,剩下的那一小步将由你迈出。本篇主要目的是体验完整的一次简单AI模型部署流程&#x…...
对撞双指针(七)三数之和
15. 三数之和 给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k ,同时还满足 nums[i] nums[j] nums[k] 0 。请你返回所有和为 0 且不重复的三元组。 注意:答案中不可以包含重复的三元组…...
【Ubuntu24.04】服务部署(虚拟机)
目录 0 背景1 安装虚拟机1.1 下载虚拟机软件1.2 安装虚拟机软件1.2 安装虚拟电脑 2 配置虚拟机2.1 配置虚拟机网络及运行初始化脚本2.2 配置服务运行环境2.2.1 安装并配置JDK172.2.2 安装并配置MySQL8.42.2.3 安装并配置Redis 3 部署服务4 总结 0 背景 你的服务部署在了你的计算…...
timm库加载的模型可视化
在深度学习中,模型的可视化有助于了解模型的结构和层级关系。以下是几种方式来可视化使用 timm 库加载的模型: 打印模型结构 torch.nn.Module 的子类(包括 timm 的模型)可以通过 print() 查看其结构:import timm# 加…...
服务限流、降级、熔断-SpringCloud
本文所使用的组件:Nacos(服务中心和注册中心)、OpenFeign(服务调用)、Sentinel(限流、降级)、Hystrix(熔断) 项目结构: service-provider:提供服…...
2024最新YT-DLP使用demo网页端渲染
2024最新YT-DLP使用demo网页端渲染 前提摘要1.使用python的fastapi库和jinjia2库进行前端渲染2.代码实现1)目录结构2)代码style.cssindex.htmlresult.htmlmain.pyrun.py 3)运行测试命令端运行 3.项目下载地址 前提摘要 2024最新python使用yt…...
《第十部分》1.STM32之通信接口《精讲》之IIC通信---介绍
经过近一周的USART学习,我深刻体会到通信对单片机的重要性。它就像人类的手脚和大脑,只有掌握了通信技术,单片机才能与外界交互,展现出丰富多彩的功能,变得更加强大和实用。 单片机最基础的“语言”是二进制。可惜&am…...
wireshark使用lua解析自定义协议
wireshark解析自定义协议 1.自定义的lua放入路径2.修改init.lua2.1 开启lua2.2 init.lua文件最后加入自己的lua文件位置,这里需要确保与自己的文件名相同 3.编写lua4.编写c抓包5.wireshark添加自定义协议如何加调试信息 1.自定义的lua放入路径 一般是自己软件的安装…...
(Keil)MDK-ARM各种优化选项详细说明、实际应用及拓展内容
参考 MDK-ARM各种优化选项详细说明、实际应用及拓展内容 本文围绕MDK-ARM优化选项,以及相关拓展知识(微库、实际应用、调试)进行讲述,希望对你今后开发项目有所帮助。 1 总述 我们所指的优化,主要两方面: 1.代码大小(Size) 2.代码性能(运行时间) 在MDK-ARM中,优…...
Qt实现可拖拽的矩形
之前项目上需要用Qt来绘制可拖拽改变形状的矩形。看了Qt Graphics相关的内容,虽然对Qt怎么添加图元的有了些了解,但是具体如何实现拖拽效果,一时也没有什么好的想法。还好网上有人分享的例子,很受启发。后来又回顾了一下这部分的代…...
CentOS:A服务器主动给B服务器推送(上传),B服务器下载A服务器文件(下载)
Linux:常识(bash: ip command not found )_bash: ip: command not found-CSDN博客 rsync 中断后先判断程序是否自动重连:ps aux | grep rsync 查看目录/文件是否被使用(查询线程占用):lsof /usr/local/bin/mongodump/.B_database1.6uRCTp 场景:MongoDB中集合非常大需要…...
Oracle 执行计划查看方法汇总及优劣对比
在 Oracle 数据库中,查看执行计划是优化 SQL 语句性能的重要工具。以下是几种常用的查看执行计划的方法及其优劣比较: 1. 使用 EXPLAIN PLAN FOR 和 DBMS_XPLAN.DISPLAY 方法 执行 EXPLAIN PLAN FOR 语句: EXPLAIN PLAN FOR SELECT * FROM …...
TCL大数据面试题及参考答案
Mysql 索引失效的场景 对索引列进行运算或使用函数:当在索引列上进行数学运算、函数操作等,索引可能失效。例如,在存储年龄的列上建立了索引,若查询语句是 “SELECT * FROM table WHERE age + 1 = 20”,这里对索引列 age 进行了加法运算,数据库会放弃使用索引而进行全表扫…...
盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...
云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地
借阿里云中企出海大会的东风,以**「云启出海,智联未来|打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办,现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...
使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装
以下是基于 vant-ui(适配 Vue2 版本 )实现截图中照片上传预览、删除功能,并封装成可复用组件的完整代码,包含样式和逻辑实现,可直接在 Vue2 项目中使用: 1. 封装的图片上传组件 ImageUploader.vue <te…...
vue3 定时器-定义全局方法 vue+ts
1.创建ts文件 路径:src/utils/timer.ts 完整代码: import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...
C++ 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
(转)什么是DockerCompose?它有什么作用?
一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...
什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南
文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果
求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如,已知表达式3*52,依照子表达式的求值顺序,有两种可能的结果,如图9-3所示。 如果乘法先执行,结果是17。如果5…...
Caliper 配置文件解析:fisco-bcos.json
config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...
