行为树详解(6)——黑板模式

【动作节点数据共享】

行为树中需要的参数可以来自游戏中的各个模块,如果仅需从多个模块获取少量参数,那么可以直接在代码中调用其他模块的单例继而层层调用获取数据。

如果获取的参数量很大,从架构上看,我们需要通过加一个中间者去管理各个模块的参数获取调用,行为树从中间者获取数据即可。

换一种说法就是要有共享数据的地方,通常会采用黑板模式。

综合来说,存在以下情况:

  1. 多个不同的动作节点或条件节点需要获取或设置来自不同模块的属性
  2. 多个不同的动作节点或条件节点会获取或设置相同模块的同一属性
  3. 不同动作节点之间有通信,A动作节点生成的临时数据是B动作节点所需的数据
  4. 不同动作节点存在大量重复计算,例如距离计算
  5. 多个动作节点会共用临时存在的多个数据

针对这些情况,我们可以通过键值对的形式实现黑板模式

需要注意的是,这些黑板不属于节点,考虑到不同行为树也会共享数据,因此也不一定属于黑板。需要有一个黑板的管理者来做数据管理。

黑板模式的数据管理本质还是通过键值对的方式,为处理不同的情况,我们需要对每种情况提供不同的Key。这和MVC中的数据管理并无本质区别。

和节点参数配置不同的是,这里是要程序做控制的,而且不确定性更大,无法做明确的规定。

在这种情况下,我们需要对每个数据做单独得ID定义,每个数据有各自的获取设置方法,通过ID映射。

根据行为树ID,节点ID,数据ID,方法ID可以实现不同的数据获取,程序只需实现方法ID即可。

在黑板中,我们需要根据这些参数生成唯一的Key,这里自然而然的就会需要对参数做封装,用泛型,用对象池。

同样的,我们需要有这些参数对应的结果,考虑数据类型差异,结果有效性等,自然也需要做封装。

【动作节点的实现位置】

在整个游戏中,与角色相关的模块如下:

  • 角色动画,基于状态机提供动作切换,提供最基础的接口
  • 角色运动,包括基础移动(走、跑等),地形移动(蹲下、跳跃、攀爬等),寻路。会调用角色动画提供的接口
  • 角色交互:
    • 与物体的交互(拾取、推开、握住、抓住、攀绕、踢开等等)。会调用角色动画或角色运动提供的接口,前者为主
    • 与角色的交互(主要是打击、少量握手、拥抱等)。会调用角色动画或角色运动提供的接口,前者为主
  • 角色技能:技能、Buff、伤害计算、效果表现。会调用角色动画或角色运动或角色交互提供的接口,前者为主
  • 角色属性:记录角色的各类状态
  • 角色行为:这里就是角色AI,会调用角色动画或角色运动或角色交互或角色技能或角色属性提供的接口

因此,在实现动作节点时,属于其他模块的直接调用其他模块的接口或在其他模块内实现,属于角色行为的在动作节点内实现。

例如,就技能而言,对角色技能来说不同角色的技能各有差异,要做不同的实现;但对角色AI而言,只有普攻、1技能、2技能、大招等

【代码实现】

数据配置

    [Serializable]
    public class DataConfig
    {
        public int dataId;
        public int setMethodId;
        public int getMethodId;
        public DataLife dataLife;
        public bool multi;//同一类型参数,参数值不同,结果不同
        public bool praseType;//如果解析类型,做自动化生成
        public bool cache;//是否做数据缓存
    }

    public enum DataLife
    {
        Persistent,//永久性数据
        Conditional,//条件性数据,满足某条件出现,不满足消失
        FixedTime,//固定时间内有效的数据
        FixedFrame,//固定帧数内有效的数据
    }

    [CreateAssetMenu(fileName = "BlackBoard_Data_Config", menuName = "BT/BlackBoardDataConfig")]
    public class BlackBoardDataConfig:ScriptableObject
    {
        public List<DataConfig> dataConfigs = new List<DataConfig>();
    }

数据请求

    public class BBDataRequest
    {
        public int btId;
        public int nodeId;
        public int dataId;

        public virtual void Release() { }
    }

    public class BBDataRequest<Parmas> : BBDataRequest
    {
        private static ObjectPool<BBDataRequest<Parmas>> Pool = new ObjectPool<BBDataRequest<Parmas>>(GenBBDataRequest);

        private static BBDataRequest<Parmas> GenBBDataRequest()
        {
            return new BBDataRequest<Parmas>();
        }

        public static BBDataRequest<Parmas> GetBBDataRequest()
        {
            return Pool.Get();
        }

        public static void Release(BBDataRequest<Parmas> data)
        {
            data.Reset();
            Pool.Release(data);
        }

        public virtual int TryAddParams(Parmas data)
        {
            return -1;
        }

        public virtual int TryAddObject(object data)
        {
            return -1;
        }

        public virtual Parmas GetParmas(int index)
        {
            return default(Parmas);
        }

        public virtual object GetObject(int index)
        {
            return null;
        }

        public override void Release()
        {
            Release(this);
        }

        public virtual void Reset()
        {

        }

    }
    public class BBDataRequestSingle<Parmas> : BBDataRequest<Parmas>
    {
        public Parmas reqParamsNoBoxing;
        public object reqParams;

        public override int TryAddParams(Parmas data)
        {
            reqParamsNoBoxing = data;
            return -1;
        }

        public override int TryAddObject(object data)
        {
            reqParams = data;
            return -1;
        }

        public override Parmas GetParmas(int index)
        {
            return reqParamsNoBoxing;
        }

        public override object GetObject(int index)
        {
            return reqParams;
        }

        public override void Reset()
        {
            reqParamsNoBoxing = default(Parmas);
            reqParams = default(object);
        }
    }

    public class BBDataRequestMulti<Parmas>:BBDataRequest<Parmas>
    {
        public Dictionary<Parmas,int> paramsNoBoxingIndex = new Dictionary<Parmas,int>();
        public Dictionary<object,int> paramsIndex = new Dictionary<object,int>();

        private Dictionary<int, Parmas> index2ParamsNoBoxing = new Dictionary<int, Parmas>();
        private Dictionary<int,object> index2Params = new Dictionary<int,object>();
        public override int TryAddParams(Parmas data)
        {
            if(!paramsNoBoxingIndex.TryGetValue(data,out int res))
            {
                res = paramsNoBoxingIndex.Count;
                paramsNoBoxingIndex[data] = res;
                
            }
            index2ParamsNoBoxing[res] = data;
            return res;
        }

        public override int TryAddObject(object data)
        {
            if(!paramsIndex.TryGetValue(data,out int res))
            {
                res = paramsIndex.Count;
                paramsIndex[data] = res;
            }
            index2Params[res] = data;
            return res;
        }

        public override object GetObject(int index)
        {
            return index2Params[index];
        }

        public override Parmas GetParmas(int index)
        {
            return index2ParamsNoBoxing[index];
        }

        public override void Reset()
        {
            paramsIndex.Clear();
            index2Params.Clear();
            index2ParamsNoBoxing.Clear();
            paramsNoBoxingIndex.Clear();
        }

    }

数据结果

    public class BBDataResult<Result> : IBBDataResult
    {
        public int dataId { get; set; }

        public DataConfig config { get; set; }

        public BBDataRequest request { get; set; }  

        public float lifeTime;
        public float curTime;
        public int curFrame;
        public bool Valid()
        {
            switch(config.dataLife)
            {
                case DataLife.FixedTime:
                case DataLife.FixedFrame:
                    return curTime > lifeTime;
                case DataLife.Conditional:
                case DataLife.Persistent: return true;
            }
            return true;  
        }

        public virtual bool Getted(int frameCount, int index)
        {
            return false;
        }

        public virtual Result GetCurResult(int index)
        {
            return default(Result);
        }

        public virtual void SetGetResult(Result value, int index)
        {

        }

        public virtual void SetCurResult(Result value,int index)
        {

        }

        public virtual void Tick(float deltaTime)
        {
            curFrame = Time.frameCount;
            if (config.dataLife == DataLife.FixedTime)
            {
                curTime += deltaTime;
            }
            if(config.dataLife == DataLife.FixedFrame)
            {
                curTime += 1;
            }
        }

        public virtual void Reset()
        {
            curTime = 0;
            curFrame = 0;
        }

        private static ObjectPool<BBDataResult<Result>> Pool = new ObjectPool<BBDataResult<Result>>(GenBBDataResult);

        private static BBDataResult<Result> GenBBDataResult()
        {
            return new BBDataResult<Result>();
        }

        public static BBDataResult<Result> GetBBDataResult()
        {
            return Pool.Get();
        }

        public static void Release(BBDataResult<Result> bbDataResult)
        {
            bbDataResult.Reset();
            Pool.Release(bbDataResult);
        }

        public void Release()
        {
            Release(this);
        }


    }

    public class BBDataResultSingle<Result>: BBDataResult<Result>
    {

        public Result result;

        public bool getted;

        public override void SetGetResult(Result value, int index)
        {
            result = value;
            getted = true;
        }

        public override void SetCurResult(Result value,int index)
        {
            result = value;
            getted = false;
        }

        public override bool Getted(int frameCount, int index)
        {
            return getted && frameCount == curFrame;
        }

        public override void Tick(float deltaTime)
        {
            base.Tick(deltaTime);
            getted = false;
        }

        public override void Reset()
        {
            getted = false;
            result = default(Result);
        }

        public override Result GetCurResult(int index)
        {
            return result;
        }
    }

    public class BBDataResultMulti<Result>: BBDataResult<Result>
    {
        public Dictionary<int,Result> resultIndex = new Dictionary<int,Result>();
        public Dictionary<int, bool> getted = new Dictionary<int, bool>();

        public override void SetGetResult(Result value,int index)
        {
            resultIndex[index] = value;
            getted[index] = true;
        }

        public override void SetCurResult(Result value, int index)
        {
            resultIndex[index] = value;
            getted[index] = false;
        }

        public override bool Getted(int frameCount,int index)
        {
            return getted[index] && frameCount == curFrame;
        }

        public override void Tick(float deltaTime)
        {
            base.Tick(deltaTime);
            foreach (var item in getted.Keys)
            {
                getted[item] = false;
            }
        }

        public override void Reset()
        {
            getted.Clear();
            resultIndex.Clear();
        }

        public override Result GetCurResult(int index)
        {
            return resultIndex[index];
        }
    }

黑板类及其管理者

    public class BlackBoardManager
    {
        private static BlackBoardManager instance;
        private BlackBoardManager() { }

        public static BlackBoardManager Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new BlackBoardManager();
                }
                return instance;
            }
        }

        public Dictionary<int, BlackBoard> id2BB = new Dictionary<int, BlackBoard>();

        private Dictionary<int,DataConfig> dataConfig = new Dictionary<int, DataConfig>();

        public void Init()
        {
            BlackBoard bb = new BlackBoard();
            bb.bbId = 1;
            id2BB[1] = bb;
            //load配置数据           
        }

        public void Tick(float deltaTime)
        {
            foreach (var bb in id2BB.Values)
            {
                bb.Tick(deltaTime);
            }
        }

        public BlackBoard CreateBlackBoard(bool common)
        {
            if (common)
            {
                return id2BB[1];
            }
            else
            {
                BlackBoard bb = new BlackBoard();
                bb.bbId = id2BB.Count + 1;
                id2BB[bb.bbId] = bb;
                return bb;
            }
        }

        public BlackBoard GetBlackBoard(int bbId)
        {
            id2BB.TryGetValue(bbId, out var bb);
            return bb;
        }

        public DataConfig GetDataConfig(int id)
        {
            return dataConfig[id];
        }

        public void RemoveBlackBoard(BlackBoard bb)
        {
            id2BB.Remove(bb.bbId);
        }

        public void Clear()
        {
            foreach(var bb in id2BB.Values)
            {
                bb.Clear();
            }
            id2BB.Clear();
            dataConfig.Clear();
        }
    }
 
    public class BlackBoard
    {
        public int bbId;

        public Dictionary<int, IBBDataResult> id2Result = new Dictionary<int, IBBDataResult>();

        public Dictionary<int,BBDataRequest> id2Request;//这里简单根据Id做划分,可以做更复杂的分类,以便于收集数据做数据分析或Debug

        private List<int> waitRemoveList = new List<int>();

        private List<BBDataRequest> reqHistory = new List<BBDataRequest>();//可以收集数据做分析

        public void Tick(float deltaTime)//Tick检查去掉无效数据
        {
            waitRemoveList.Clear();
            foreach (var item in id2Result)
            {
                item.Value.Tick(deltaTime);
                if(!item.Value.Valid())
                {
                    waitRemoveList.Add(item.Key);
                }
            }
            foreach (var item in waitRemoveList)
            {
                RemoveData(item);
            }
        }

        public Result GetData<Params,Result>(int btId,int nodeId,int dataId, Params reqparams,out bool valid)
        {
            var config = BlackBoardManager.Instance.GetDataConfig(dataId);//根据数据Id获取数据配置
            var request = GetBBDataRequest<Params>(btId,nodeId,dataId,reqparams,config.multi && config.cache, out int index);//根据参数获取请求,分为Single请求和Multi请求
            var result = GetBBDataResult<Result>(dataId, config, request);//获取请求对应的结果

            //一个数据Id只有一个对应的请求和结果
            valid = result.Valid();
            if(valid)
            {
                if(config.praseType)
                {
                    BBDataMethod.DispatchMethoId<Params,Result>(result.config.getMethodId, bbId, dataId, index, true);//自动解析传入的参数和结果的类型,自动化生成代码,适用于简单的值类型
                }
                else
                {
                    BBDataMethod.DispatchMethoId(result.config.getMethodId, bbId, dataId, index);//自定义处理数据类型
                }
               
                return ((BBDataResult<Result>)result).GetCurResult(index);//同一个数据Id,在获取时会传入不同的参数,在请求中,给参数生成Index,根据Index获取其对应的结果
            }    
            return default(Result);
        }

        public Result GetData<Result>(int btId, int nodeId, int dataId, object reqparams, out bool valid)
        {
            var config = BlackBoardManager.Instance.GetDataConfig(dataId);
            var request = GetBBDataRequest(btId, nodeId, dataId, reqparams, config.multi && config.cache, out int index);
            var result = GetBBDataResult<Result>(dataId, config, request);
            valid = result.Valid();
            if (valid)
            {
                if (config.praseType)
                {
                    BBDataMethod.DispatchMethoId<object, Result>(result.config.getMethodId, bbId, dataId, index, true);
                }
                else
                {
                    BBDataMethod.DispatchMethoId(result.config.getMethodId, bbId, dataId, index);
                }
                return ((BBDataResult<Result>)result).GetCurResult(index);
            }
            return default(Result);

        }

        public void SetData<Params, Value>(int btId, int nodeId, int dataId,Value value, Params reqparams = default)
        {
            var config = BlackBoardManager.Instance.GetDataConfig(dataId);//根据数据Id获取数据配置
            var request = GetBBDataRequest<Params>(btId, nodeId, dataId, reqparams, config.multi && config.cache, out int index);//根据参数获取请求,分为Single请求和Multi请求
            var result = GetBBDataResult<Value>(dataId, config, request);//获取请求对应的结果

            if (!((BBDataResult<Value>)result).GetCurResult(index).Equals(value))//判断设置的值是否和当前的结果值相当,如果相等就不用再设置了
            {
                if (config.praseType)
                {
                    BBDataMethod.DispatchMethoId<Params, Result>(result.config.setMethodId, bbId, dataId, index, false);
                }
                else
                {
                    BBDataMethod.DispatchMethoId(result.config.setMethodId, bbId, dataId, index);
                }
            }         
        }

        public void SetData<Value>(int btId, int nodeId, int dataId, Value value,object reqparams = null)
        {
            var config = BlackBoardManager.Instance.GetDataConfig(dataId);
            var request = GetBBDataRequest(btId, nodeId, dataId, reqparams, config.multi && config.cache, out int index);
            var result = GetBBDataResult(dataId, config, request);
            if (!((BBDataResult<Value>)result).GetCurResult(index).Equals(value))
            {
                if (config.praseType)
                {
                    BBDataMethod.DispatchMethoId<object, Result>(result.config.setMethodId, bbId, dataId, index, false);
                }
                else
                {
                    BBDataMethod.DispatchMethoId(result.config.setMethodId, bbId, dataId, index);
                }
            }
        }

        public bool RemoveData(int dataId)
        {
            int count = 0;
            if(id2Result.TryGetValue(dataId,out var result))
            {
                result.Release();
                id2Result.Remove(dataId);
                count++;
            }

            if(id2Request.TryGetValue(dataId,out var request))
            {
                request.Release();
                id2Request.Remove(dataId);
                count++;
            }

            return count == 2;
        }

        public BBDataRequest GetDataRequest(int dataId)
        {
            id2Request.TryGetValue(dataId, out var result);
            return result;
        }

        public IBBDataResult GetDataResult(int dataId)
        {
            id2Result.TryGetValue(dataId, out var result);
            return result;
        }

        public void Clear()
        {
            id2Request.Clear();
            id2Result.Clear();
            waitRemoveList.Clear();
            //SaveHistory
            reqHistory.Clear();
        }

        private BBDataRequest GetBBDataRequest<T>(int btId, int nodeId, int dataId,T data,bool multi,out int index)
        {
            if(!id2Request.TryGetValue(dataId,out var request))
            {
                request = multi ? BBDataRequestMulti<T>.GetBBDataRequest() : BBDataRequestSingle<T>.GetBBDataRequest();
                request.btId = btId;
                request.nodeId = nodeId;
                request.dataId = dataId;
                //reqHistory.Add(request);
            }
            var res = request as BBDataRequest<T>;
            index = res.TryAddParams(data);//将获取数据传入的参数封装在 BBDataRequest中
            return res;
        }

        private BBDataRequest GetBBDataRequest(int btId, int nodeId, int dataId, object data,bool multi,out int index)
        {
            if (!id2Request.TryGetValue(dataId, out var request))
            {
                request = multi ? BBDataRequestMulti<object>.GetBBDataRequest() : BBDataRequestSingle<object>.GetBBDataRequest();
                request.btId = btId;
                request.nodeId = nodeId;
                request.dataId = dataId;
                //reqHistory.Add(request);
            }
            var res = request as BBDataRequest<object>;
            index = res.TryAddObject(data);
            return res;
        }

        private IBBDataResult GetBBDataResult<T>(int dataId,DataConfig config,BBDataRequest request)
        {
            if (!id2Result.TryGetValue(dataId, out var result))
            {
                BBDataResult<T> res = (config.multi && config.cache) ? BBDataResultMulti<T>.GetBBDataResult() : BBDataResultSingle<T>.GetBBDataResult();
                if (!config.cache) res.SetCurResult(default(T), 0);
                result = res;
                result.dataId = dataId;
                result.config = config;
            }
            result.request = request;
            return result;
        }

        private IBBDataResult GetBBDataResult(int dataId, DataConfig config, BBDataRequest request)
        {
            if (!id2Result.TryGetValue(dataId, out var result))
            {
                BBDataResult<object> res = (config.multi && config.cache) ? BBDataResultMulti<object>.GetBBDataResult() : BBDataResultSingle<object>.GetBBDataResult();
                if (!config.cache) res.SetCurResult(null, 0);
                result = res;
                result.dataId = dataId;
                result.config = config;
            }
            result.request = request;
            return result;
        }
    }

数据的GetSet方法实

    public static class BBDataDefinition
    {
        //这里通过配置自动生成
        public const int Def_获取血量 = 11223344;
        public const int Def_设置血量 = 11223345;
        public const int Def_获取资源数量 = 121212123;
        public const int Def_设置资源数量 = 121212124;

    }

    public partial class BBDataMethod
    {
        //这里通过配置自动生成

        private static Dictionary<(Type, Type), Action<BBDataRequest,IBBDataResult,int,int,bool>> TypeToPraseAction = new Dictionary<(Type, Type), Action<BBDataRequest, IBBDataResult, int, int,bool>>()
        {
            [(typeof(void),typeof(int))] = PraseVoidAndInt,
            [(typeof(int), typeof(int))] = PraseIntAndInt,
            [(typeof(int), typeof(void))] = PraseIntAndVoid,
        };

        private static Dictionary<int, Func<int>> GetIntValue = new Dictionary<int, Func<int>>()
        {
            [BBDataDefinition.Def_获取资源数量] = GetResCount,

        };

        private static Dictionary<int, Action<int>> SetIntValue = new Dictionary<int, Action<int>>()
        {
            [BBDataDefinition.Def_设置资源数量] = SetResCount,
        };

        private static Dictionary<int, Func<int,int>> GetIntValueByInt = new Dictionary<int, Func<int,int>>()
        {

        };

        private static Dictionary<int, Action<int, int>> SetIntValueByInt = new Dictionary<int, Action<int, int>>()
        {

        };

        public static void DispatchMethoId<Params,Result>(int methodId,int bbId,int dataId,int index,bool get)
        {
            var bb = BlackBoardManager.Instance.GetBlackBoard(bbId);
            var res = bb.GetDataResult(dataId);
            if (get && res != null && res.Getted(Time.frameCount, index))
            {
                return;
            }
            var req = bb.GetDataRequest(dataId);
            if (req != null && res != null)
            {
                var typeReq = typeof(Params);
                var typeRes = typeof(Result);
                TypeToPraseAction.TryGetValue((typeReq, typeRes), out var action);
                if (action != null)
                {
                    action(req, res, methodId, index, get);
                }
            }
        }

        public static void DispatchMethoId(int methodId, int bbId, int dataId, int index)
        {
            switch (methodId)
            {
                case BBDataDefinition.Def_获取血量: GetRoleHp(bbId, dataId, index); break;
                case BBDataDefinition.Def_设置血量: SetRoleHp(bbId, dataId, index); break;
            }
        }

        private static void PraseVoidAndInt(BBDataRequest req, IBBDataResult res, int methodId, int index,bool get)
        {
            if(get)
            {
                int intValue = GetIntValue[methodId].Invoke();
                var intResult = res as BBDataResult<int>;
                intResult.SetGetResult(intValue, index);
            }

        }

        private static void PraseIntAndVoid(BBDataRequest req, IBBDataResult res, int methodId, int index, bool get)
        {
            if (!get)
            {
                var intResult = res as BBDataResult<int>;
                int intValue = intResult.GetCurResult(index);
                SetIntValue[methodId].Invoke(intValue);
            }

        }

        private static void PraseIntAndInt(BBDataRequest req, IBBDataResult res, int methodId, int index, bool get)
        {
            if(get)
            {
                var intReq = req as BBDataRequest<int>;
                int intParams = intReq.GetParmas(index);
                int intValue = GetIntValueByInt[methodId].Invoke(intParams);
                var intResult = res as BBDataResult<int>;
                intResult.SetGetResult(intValue, index);
            }
            else
            {
                var intReq = req as BBDataRequest<int>;
                int intParams = intReq.GetParmas(index);
                var intResult = res as BBDataResult<int>;
                int intValue = intResult.GetCurResult(index);
                SetIntValueByInt[methodId].Invoke(intParams, intValue);
            }
        }
    }

    public partial class BBDataMethod
    {
        public static void GetRoleHp(int bbId, int dataId,int index)
        {
            var bb = BlackBoardManager.Instance.GetBlackBoard(bbId);//获取数据所在的BB
            var res = bb.GetDataResult(dataId);//获取数据对应的结果
            if(res != null && res.Getted(Time.frameCount,index))//判断当前帧该数据是否已经获取过
            {
                return;
            }
            var req = bb.GetDataRequest(dataId);//获取数据对应的请求           
            if(req != null )
            {               
                var intReq = req as BBDataRequest<int>;
                int roleId = intReq.GetParmas(index);//获取请求的参数
                int hp = 100;//通过角色Id获取角色属性,属性系统固定时,这些类似的获取值的代码都可以通过自动化配置生成            
                var intResult = res as BBDataResult<int>;
                intResult.SetGetResult(hp,index);//设置获取的结果
            }
        }

        public static void SetRoleHp(int bbId, int dataId,int index)
        {
            var bb = BlackBoardManager.Instance.GetBlackBoard(bbId);
            var res = bb.GetDataResult(dataId);
            var req = bb.GetDataRequest(dataId);
            if (req != null && res != null)
            {
                var intReq = req as BBDataRequest<int>;
                int roleId = intReq.GetParmas(index);
                var intResult = res as BBDataResult<int>;
                int hp = intResult.GetCurResult(index);             
                //调用接口设置角色血量
            }
        }

        public static int GetResCount() { return 100; }
        public static void SetResCount(int value) { }

    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/949839.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【漫话机器学习系列】039.点积(dot product)

点积&#xff08;Dot Product&#xff09; 点积是线性代数中的一种基本运算&#xff0c;用于两个向量的操作。它是将两个向量按分量相乘并求和的结果&#xff0c;用于衡量两个向量在同一方向上的相似性。 点积的定义 给定两个相同维度的向量 和 &#xff0c;它们的点积定义为…

2024年大型语言模型(LLMs)的发展回顾

2024年对大型语言模型&#xff08;LLMs&#xff09;来说是充满变革的一年。以下是对过去一年中LLMs领域的关键进展和主题的总结。 GPT-4的壁垒被打破 去年&#xff0c;我们还在讨论如何构建超越GPT-4的模型。如今&#xff0c;已有18个组织拥有在Chatbot Arena排行榜上超越原…

Visual Studio 2022 C++ gRPC 环境搭建

文章目录 1、gRPC 安装2、创建项目2.1、创建 “空的解决方案”2.2、新建 gRPCServer 和 gRPCClient 项目2.3、创建 proto 文件 2、为 gRPC 服务端和客服端项目配置 protobuf 编译2.1、protobuf 配置2.2、gRPCServer 项目配置2.3、gRPCClient 项目配置 3、测试3.1、启动服务端程…

Wasm是什么

WebAssembly 是什么&#xff1f; 1.1 WebAssembly 的定义 WebAssembly&#xff08;简称 Wasm&#xff09;是一种二进制指令格式&#xff0c;设计用于在现代 Web 浏览器中高效运行程序。它可以被认为是一种低级的、接近硬件的编程语言&#xff0c;是一种介于字节码和机器码之间…

使用深度学习来实现图像超分辨率 综述!

今天给大家介绍一篇图像超分辨率邻域的综述&#xff0c;这篇综述总结了图像超分辨率领域的几方面&#xff1a;problem settings、数据集、performance metrics、SR方法、特定领域应用以结构组件形式&#xff0c;同时&#xff0c;总结超分方法的优点与限制。讨论了存在的问题和挑…

直播预告|StarRocks 3.4,打造 AI 时代的智能数据基座,应用场景全面扩展

随着新年的到来&#xff0c;StarRocks 3.4 即将上线&#xff0c;为 AI Workload 和更多应用场景提供强大支持&#xff01;此次升级聚焦于提升 AI 场景支持&#xff0c;并扩展更多应用场景&#xff0c;全方位提升数据分析体验。 更强的 AI 场景支持&#xff1a; 引入 Vector In…

【GOOD】A Survey of Deep Graph Learning under Distribution Shifts

深度图学习在分布偏移下的综述&#xff1a;从图的分布外泛化到自适应 Northwestern University, USA Repository Abstract 图上的分布变化——训练和使用图机器学习模型之间的数据分布差异——在现实世界中普遍存在&#xff0c;并且通常不可避免。这些变化可能会严重恶化模…

【微服务】5、服务保护 Sentinel

Sentinel学习内容概述 Sentinel简介与结构 Sentinel是Spring Cloud Alibaba的组件&#xff0c;由阿里巴巴开源&#xff0c;用于服务流量控制和保护。其内部核心库&#xff08;客户端&#xff09;包含限流、熔断等功能&#xff0c;微服务引入该库后只需配置规则。规则配置方式有…

神经网络的进展与挫折

神经网络的概念可追溯到上世纪40年代,当时被认为是一种模拟大脑神经元网络的计算系统。 1940年代,麦卡洛克(McCulloch)和沃尔特皮茨(Walter Pitts)率先提出了受人类大脑和生物神经网络启发的人工神经网络。 1951年,马文明斯基(Marvin Minsky)的SNARC系统标志着第一个…

搭建企业AI助理的创新应用与案例分析

在大健康零售行业&#xff0c;企业面临着日益增长的市场需求和复杂的供应链管理挑战。AI助理的应用不仅能够提升客户服务效率&#xff0c;还能优化供应链管理&#xff0c;降低运营成本。 一、AI助理在大健康零售行业的创新应用 个性化健康咨询 AI助理可以通过分析客户的健康…

一文读懂「LoRA」:大型语言模型的低秩适应

LoRA: Low-Rank Adaptation of Large Language Models 前言 LoRA作为大模型的微调框架十分实用&#xff0c;在LoRA出现以前本人都是通过手动修改参数、优化器或者层数来“炼丹”的&#xff0c;具有极大的盲目性&#xff0c;但是LoRA技术能够快速微调参数&#xff0c;如果LoRA…

接口项目操作图-thinkphp6-rabbitmq

一、用户开户流程 用户首次需要联系商务开通账户&#xff0c;需要提供手机号及来访问的IP。开好户之后&#xff0c;平台方将提供用户访问的key值及header头部参数的公钥加密文件、body访问参数以及返回数据的公私钥加解密文件。 二、用户请求流程 用户将拿到的key值进行rsa公钥…

程序环境及预处理

一.程序的翻译环境和执行环境 在ANSI C&#xff08;标准c&#xff09;的任何一种实现中&#xff0c;存在两个不同的环境。 计算机是能够执行二进制指令的&#xff0c;但是我们写出的c语言代码是文本信息&#xff0c;计算机不能直接理解 第1种是翻译环境&#xff0c;在这个环境…

回顾 Tableau 2024 亮点功能,助力 2025 数据分析新突破

2024 年&#xff0c;Tableau 用更智能、更高效的工具&#xff0c;重新定义了数据分析的可能性。 回顾 2024 年&#xff0c;Tableau 凭借一系列创新功能&#xff0c;在数据可视化与分析领域再次引领潮流。无论是深度整合 AI 技术&#xff0c;还是优化用户体验的细节&#xff0c;…

【姿态估计实战】使用OpenCV和Mediapipe构建锻炼跟踪器【附完整源码与详细说明】

《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…

快速上手Python,制作趣味猜数字游戏

在编程学习的旅程中&#xff0c;游戏是一个极佳的切入点。今天&#xff0c;我们将一起创建一个简单而有趣的猜数字游戏&#xff0c;借此机会深入学习Python编程的基础知识和一些实用的编程技巧。无论你是初学者还是有一定基础的开发者&#xff0c;相信你都能从中获得乐趣和收获…

AI驱动的可演化架构与前端开发效率

1. 引言 在当今快节奏的数字时代&#xff0c;软件系统需要具备强大的适应能力才能在瞬息万变的市场需求中保持竞争力。软件可演化架构的重要性日益凸显&#xff0c;它能够让软件系统在面对需求变更、技术升级以及市场波动时&#xff0c;能够快速、高效地进行调整和升级&#x…

用豆包MarsCode IDE打造精美数据大屏:从零开始的指南

原标题&#xff1a;用豆包MarsCode IDE&#xff0c;从0到1画出精美数据大屏&#xff01; 豆包MarsCode IDE 是一个云端 AI IDE 平台&#xff0c;通过内置的 AI 编程助手&#xff0c;开箱即用的开发环境&#xff0c;可以帮助开发者更专注于各类项目的开发。 作为一名前端开发工…

基于RK3568/RK3588大车360度环视影像主动安全行车辅助系统解决方案,支持ADAS/DMS

产品设计初衷 HS-P2-2D是一款针对大车盲区开发的360度全景影像 安全行车辅助系统&#xff0c;通过车身四周安装的超广角像机&#xff0c;经算法合成全景鸟瞰图&#xff0c;通过鸟瞰图&#xff0c;司机非常清楚的看清楚车辆四周情况&#xff0c;大大降低盲区引发的交通事故。 产…

pygame飞机大战

飞机大战 1.main类2.配置类3.游戏主类4.游戏资源类5.资源下载6.游戏效果 1.main类 启动游戏。 from MainWindow import MainWindow if __name__ __main__:appMainWindow()app.run()2.配置类 该类主要存放游戏的各种设置参数。 #窗口尺寸 #窗口尺寸 import random import p…