【AI浅谈】AI算法,用尽可能简单的话讲懂AI的原理【2】

接上【AI浅谈】AI算法,用尽可能简单的话讲懂AI的原理【1】

事前说明

学无止尽,个人能力不足,如有错误之处烦请见谅,感谢您的阅读与指出!

PS:小伞是一直在学习的唐伞妖怪欧,由于只是一只菜菜的妖怪,所以学习的地方可能会有些不对(||๐_๐),感谢各位大佬的指正!

关于AI学习的几大注意

谈完了AI算法的基本原理,接下来我们就要从多个角度来谈谈,如何让AI模型学得更好。AI学习主要涉及到的主体有若干个:数据,模型,训练,评估,优化,按照我们上节课讲过的概念来对号入座,数据模型训练这些不用多谈,评估的话指的就是多种多样的损失函数,还有诸如准确率这些的评估依据,优化的话指的就是为了让模型训练的更好采取的各种各样的手段,例如正则化。这5个主体除了评估是事后诸葛亮,反映学习效果的好坏以外,其他4个的优化,都可以一定程度的提高AI的学习效果。

先从数据开始吧~

当然在讲问题之前,首先要有一个具体的例子,这边就假设我手里有很多水果的图片,然后要让一个模型来学会如何区分水果(假设需要让AI进行区分的总体水果种类有20种)吧。

先从数据开始讲吧,首先我手里面的数据要足够丰富多样,至少要涵盖总体的20种水果种类,假设我手里如果只有苹果和梨的照片,而其他18种水果的照片数量都很少(几张),。这样AI学习的时候,就有可能把其他18种水果种类的照片认为是噪声,然后忽略掉了,这可不是我们想要的情况。

而上面说明的情况就引出了一个著名的问题,叫做样本不均衡问题,指的是我们手里面的数据集,它的样本数量是不均衡的,在这个例子里面,苹果跟梨的数量偏多,而其他水果的数量偏少,换而言之模型只有很少的机会会接触到其他水果,这样模型在猜水果的过程中,久而久之可能就会只猜是苹果或者是梨,其他的可能忽略掉了,因为这样子学得更快,也不用背很多东西。针对这种情况,我们可以采用欠采样或者过采样的策略。

欠采样

欠采样的概念很简单,就是我每次从较多的类别中取出跟较少的类别一样的数目,从上面的例子来说,假设这20种水果种类里面最少的是猕猴桃,只有大概7张照片,这种情况我就从其他19种里面都抽出7张(随机抽的),组合成一个很小的数据集来送给AI模型进行训练,这样做的好处是样本数据一定是均衡的,但是欠采样可能会造成一个问题,就是对于多数类样本里面,AI学习的可能不全,从上面的例子来说,假设苹果的数量有2万张,我们只从2万张里面取7张,那么AI可能只学习到了苹果是一个圆形且红色的东西,那么当他看到圣女果的时候,可能也会把圣女果认成是苹果。这就是欠采样的缺点。

过采样

但还有一种方法叫做过采样。过采样的方法简单粗暴,既然数量不够,那我就不断复制粘贴,把少数类的样本通过不断重复增加到跟多数类一样的数量。例如猕猴桃只有7张,苹果有3000张,那这个时候我就把猕猴桃里面的数据不断复制粘贴复制粘贴,构造一堆样本出来,增加到3000张为止,这样做的好处是AI可以在样本数量大并且样本均衡的数据集里进行学习,并且不会出现欠拟合的情况,缺点是由于AI看多了重复的样本,它可能会出现过拟合的情况(干脆背起来算了,失去了泛化性).

当然关于样本不均衡问题的解决方法,还有好几种,这是一个大问题,我们下次再谈。

To Be Continue...

在C语言中实现行为树(Behavior Tree)的游戏AI逻辑可以相对复杂,因为C不是设计用于图形化编程的语言,但它仍然可以编写基本的控制结构。由于这是一个简化的例子,我们假设行为树有三种基础节点:选择、顺序执行和动作节点。 ```c typedef enum { IDLE, SEARCH, ATTACK } AIState; typedef struct Node { void (*execute)(void); AIState state; } TreeNode; // 动作节点示例,这里仅表示向前移动 void moveForward(TreeNode* node) { // 简化版的前进操作 printf("AI moving forward.\n"); } // 行为树节点 struct BehaviorTree { TreeNode* root; }; // 行为树创建一个搜索节点,如果找不到敌人则切换到IDLE TreeNode* searchEnemy(BehaviorTree* bt) { TreeNode* searchNode = (TreeNode*)malloc(sizeof(TreeNode)); searchNode->execute = &findEnemy; // 假设有一个findEnemy函数查找敌人 searchNode->state = SEARCH; return searchNode; } // 行为树创建一个序列节点,先搜索再攻击 TreeNode* makeSequence(BehaviorTree* bt) { TreeNode* sequence = (TreeNode*)malloc(sizeof(TreeNode)); sequence->root = searchEnemy(bt); // 创建搜索节点 sequence->execute = &executeSequence; // 假设executeSequence处理序列执行 sequence->state = SEQUENCE; // 假设SEQUENCE代表执行顺序 return sequence; } // 伪函数,展示如何执行行为树 void executeBehaviorTree(BehaviorTree* bt) { if (bt->root == NULL) return; bt->root->execute(); // 根据当前状态执行相应的行为 } int main() { BehaviorTree ai; ai.root = makeSequence(&ai); // 初始化行为树 while (true) { executeBehaviorTree(&ai); // 游戏主循环,可能需要检查是否需要更新AI状态或切换到IDLE if (!findEnemy()) ai.root->state = IDLE; } return 0; } ``` 请注意,这只是一个非常基础的示例,实际游戏中你需要实现更复杂的搜索、攻击、躲避等行为,并管理状态转换。此外,行为树的真正实现通常会涉及到递归和数据结构的更新,而这超出了C语言的基础语法范围。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值