国产av一二三区|日本不卡动作网站|黄色天天久久影片|99草成人免费在线视频|AV三级片成人电影在线|成年人aV不卡免费播放|日韩无码成人一级片视频|人人看人人玩开心色AV|人妻系列在线观看|亚洲av无码一区二区三区在线播放

網(wǎng)易首頁(yè) > 網(wǎng)易號(hào) > 正文 申請(qǐng)入駐

Unity中利用遺傳算法訓(xùn)練MLP

0
分享至


【USparkle專欄】如果你深懷絕技,愛(ài)“搞點(diǎn)研究”,樂(lè)于分享也博采眾長(zhǎng),我們期待你的加入,讓智慧的火花碰撞交織,讓知識(shí)的傳遞生生不息!

這是侑虎科技第1843篇文章,感謝作者狐王駕虎供稿。歡迎轉(zhuǎn)發(fā)分享,未經(jīng)作者授權(quán)請(qǐng)勿轉(zhuǎn)載。如果您有任何獨(dú)到的見(jiàn)解或者發(fā)現(xiàn)也歡迎聯(lián)系我們,一起探討。(QQ群:793972859)

作者主頁(yè):

https://home.cnblogs.com/u/OwlCat

梯度下降法訓(xùn)練神經(jīng)網(wǎng)絡(luò)通常需要我們給定訓(xùn)練的輸入-輸出數(shù)據(jù),而用遺傳算法會(huì)便捷很多,它不需要我們給定好數(shù)據(jù),只需要隨機(jī)化多個(gè)權(quán)重進(jìn)行N次“繁衍進(jìn)化”,就可以得出效果不錯(cuò)的網(wǎng)絡(luò)。

這種訓(xùn)練方式的好處就是不需要訓(xùn)練用的預(yù)期輸出數(shù)據(jù),適合那類可以簡(jiǎn)單通過(guò)環(huán)境交互判斷訓(xùn)練好壞的神經(jīng)網(wǎng)絡(luò)AI。當(dāng)然,壞處就是訓(xùn)練的時(shí)間可能需要很長(zhǎng),尤其是神經(jīng)網(wǎng)絡(luò)比較龐大時(shí)。

完整項(xiàng)目gitee鏈接:


https://gitee.com/OwlCat/some-projects-in-tutorials/tree/master/ANNGA

一、用Compute Shader實(shí)現(xiàn)神經(jīng)網(wǎng)絡(luò)

神經(jīng)網(wǎng)絡(luò)的計(jì)算一般都用矩陣優(yōu)化,像Python語(yǔ)言者學(xué)習(xí)實(shí)現(xiàn)神經(jīng)網(wǎng)絡(luò)時(shí),通常會(huì)借助NumPy的Torch進(jìn)行計(jì)算,加速運(yùn)算過(guò)程。


個(gè)人曾經(jīng)嘗試過(guò)以單個(gè)神經(jīng)元為最小單位實(shí)現(xiàn)的神經(jīng)網(wǎng)絡(luò),但其實(shí)這種做法并不好。后來(lái)嘗試過(guò)使用C#的MathNet庫(kù)中的矩陣,但發(fā)現(xiàn)它并沒(méi)有在硬件層面對(duì)矩陣運(yùn)算進(jìn)行加速。雖說(shuō)對(duì)于小規(guī)模網(wǎng)絡(luò),即便不加速計(jì)算也不會(huì)太影響性能,但總覺(jué)得得考慮的更長(zhǎng)遠(yuǎn)些。

想到神經(jīng)網(wǎng)絡(luò)的預(yù)測(cè)過(guò)程中,其實(shí)我們只關(guān)心輸入層與輸出層,而隱藏層的那些計(jì)算結(jié)果其實(shí)根本不在乎。這似乎很適合用Compute Shader來(lái)完成!

隱藏層計(jì)算的結(jié)果完全可以只留在ComputeBuffer,只有輸入層需要將數(shù)據(jù)寫(xiě)入以及輸出層將結(jié)果讀取,CPU與GPU間數(shù)據(jù)的傳遞并不會(huì)很多;而且Compute Shader強(qiáng)大的并行計(jì)算能力也可以加速我們的運(yùn)算過(guò)程。

但由于本文主要還是想講遺傳算法,就不喧賓奪主了。

二、遺傳算法

在中學(xué)生物課本有提到達(dá)爾文的自然選擇學(xué)說(shuō)四個(gè)主要觀點(diǎn):過(guò)度繁殖、生存競(jìng)爭(zhēng)、遺傳和變異、適者生存。遺傳算法就是借鑒了其中的思想,它的整個(gè)流程極其相似:

1. 初始化種群

在本例中,我們想要獲取神經(jīng)網(wǎng)絡(luò)中各層合適的權(quán)重與偏置的值,來(lái)使神經(jīng)網(wǎng)絡(luò)的輸出符合預(yù)期,所以我們將整個(gè)神經(jīng)網(wǎng)絡(luò)的所有權(quán)重與偏置視為一個(gè)個(gè)體。

using System; using System.Collections; using System.Collections.Generic; using UnityEngine; namespace JufGame {     [CreateAssetMenu(menuName = ("JufGame/AI/ANN/WeightBias"), fileName = ("WeightAndBias_"))]     publicclassWeightBiasMemory : ScriptableObject     {         [Serializable]         public struct LayerWeightAndBias         {             publicint inputCount;             publicint outputCount;             publicfloat[] weights;             publicfloat[] bias;         }         [Tooltip("各全連層的權(quán)重和偏置")]         public LayerWeightAndBias[] WeiBiasArray;         [Tooltip("全連接層的Compute Shader")]         public ComputeShader affine;         [Tooltip("激活函數(shù)的Compute Shader")]         public ComputeShader activateFunc;         [Tooltip("損失函數(shù)的Compute Shader)]         public ComputeShader lossFunc;         [Tooltip("當(dāng)前損失函數(shù)在反向傳播時(shí)是否要載入上次輸出,用于sigmoid等函數(shù)")]         public bool isLoadLastOutput;         [Header("隨機(jī)初始化權(quán)重")]         [Tooltip("是否要隨機(jī)初始化")]         public bool isRandomWeightAndBias = false;         [Tooltip("當(dāng)前權(quán)重是否是訓(xùn)練成功后的")]         public bool isFinishedWeightAndBias = false;         [Tooltip("隨機(jī)初始化的最大值和最小值")]         public float minRandValue = -1, maxRandValue = 1;         [Tooltip("是否隨機(jī)化權(quán)重")]         public bool isRandomBias = false;         private void OnValidate()         {             if(isRandomWeightAndBias && !isFinishedWeightAndBias)             {                 RandomWeightAndBias(ref WeiBiasArray, minRandValue, maxRandValue, isRandomBias);                 isRandomWeightAndBias = false;             }         }         ///         /// 隨機(jī)初始化權(quán)重和偏置         ///         /// WeiBiasArray">被隨機(jī)化的數(shù)層權(quán)重和偏置         /// minRandValue">最小隨機(jī)值         /// maxRandValue">最大隨機(jī)值         /// isRandomBias">偏置是否也要隨機(jī)化,如果false則置0         public static void RandomWeightAndBias(ref LayerWeightAndBias[] WeiBiasArray, float minRandValue,              float maxRandValue, bool isRandomBias = false)         {             var rand = new System.Random();             foreach (var wb in WeiBiasArray)             {                 float range = maxRandValue - minRandValue;                 // 初始化權(quán)重                 for (int i = 0; i < wb.weights.Length; ++i)                 {                     wb.weights[i] = (float)(rand.NextDouble() * range + minRandValue); // 使用指定范圍生成隨機(jī)數(shù)                 }                 // 初始化偏置                 for (int i = 0; i < wb.bias.Length; ++i)                 {                     wb.bias[i] = isRandomBias ?  (float)(rand.NextDouble() * range + minRandValue) : 0;                 }             }         }         ///         /// 深拷貝所有層的權(quán)重與偏置         ///         /// source">拷貝源         /// target">目標(biāo)處         public static void DeepCopyAllLayerWB(ref LayerWeightAndBias[] source, ref LayerWeightAndBias[] target)         {             for(int i = 0, j; i < source.Length; ++i)             {                 var wb = target[i];                 for (j = 0; j < wb.weights.Length; ++j)                 {                     wb.weights[j] = source[i].weights[j];                 }                 for (j = 0; j < wb.bias.Length; ++j)                 {                     wb.bias[j] = source[i].bias[j];                 }             }         }         ///         /// 交換所有層的權(quán)重與偏置         ///         public static void DeepSwap(ref LayerWeightAndBias[] a, ref LayerWeightAndBias[] b)         {             float tp;             for(int i = 0, j; i < a.Length; ++i)             {                 var wb = b[i];                 for (j = 0; j < wb.weights.Length; ++j)                 {                     tp = wb.weights[j];                     wb.weights[j] = a[i].weights[j];                     a[i].weights[j] = tp;                 }                 for (j = 0; j < wb.bias.Length; ++j)                 {                     tp = wb.bias[j];                     wb.bias[j] = a[i].bias[j];                     a[i].bias[j] = tp;                 }             }         }     } }

using System.Collections; using System.Collections.Generic; using UnityEngine; namespace JufGame {     //遺傳算法中的個(gè)體,具體邏輯需繼承該類擴(kuò)展     publicclassGAUnit : MonoBehaviour     {         public WeightBiasMemory memory;         publicfloat FitNess;         public bool isOver;         public virtual voidReStart()         {             isOver = false;             FitNess = 0;         }     } }

然后初始化指定數(shù)量的該類個(gè)體作為初始種群,擔(dān)任原始父本,并讓個(gè)體權(quán)重與偏置隨機(jī)化。這樣一來(lái),每個(gè)個(gè)體就都是不同的了,至于它們中誰(shuí)具有更好的潛質(zhì),就需要通過(guò)競(jìng)爭(zhēng)得知了。

2. 競(jìng)爭(zhēng)

我們讓游戲中的使用神經(jīng)網(wǎng)絡(luò)決策的AI個(gè)體,分別應(yīng)用種群中各個(gè)體作為神經(jīng)網(wǎng)絡(luò)的權(quán)重與偏置,并直接應(yīng)用神經(jīng)網(wǎng)絡(luò)進(jìn)行決策。由于這些權(quán)重與偏置都是隨機(jī)的,執(zhí)行的效果幾乎都不堪入目。

private voidFixedUpdate() {     if(isEndTrain) //如果選擇結(jié)束訓(xùn)練,則保留當(dāng)前最好的個(gè)體     {         SaveBest();     }     elseif(TrainUnit.isOver) //如果當(dāng)前訓(xùn)練單位的訓(xùn)練結(jié)束     {         parents[curIndex].fitness = TrainUnit.FitNess;         TrainUnit.ReStart();         //輪流將當(dāng)前父本中個(gè)體權(quán)重與偏置賦給訓(xùn)練單位進(jìn)行決策         if(++curIndex < AllPopulation)         {             WeightBiasMemory.DeepCopyAllLayerWB(ref parents[curIndex].WB, ref TrainUnit.memory.WeiBiasArray);         }         //……     } }

但我們需要“矮子里拔高個(gè)”,設(shè)計(jì)一個(gè)評(píng)估函數(shù)計(jì)算每個(gè)個(gè)體的適應(yīng)度。比如評(píng)估一個(gè)小車,我們就可以通過(guò)它行駛的距離、速度等進(jìn)行加權(quán)和得到一個(gè)適應(yīng)度。總之,要確保評(píng)估函數(shù)的計(jì)算結(jié)果能合理表達(dá)出決策結(jié)果的好壞。

3. 繁殖與變異

現(xiàn)在,我們要隨機(jī)從原始父本中選出兩個(gè)不同的個(gè)體,進(jìn)行繁殖得到兩個(gè)新的個(gè)體。

這個(gè)繁殖的過(guò)程很簡(jiǎn)單,與染色體互換的過(guò)程極其相似。對(duì)于新權(quán)重和偏置,隨機(jī)從兩個(gè)作為父本的個(gè)體選擇一個(gè),選取其對(duì)應(yīng)部分的值。每個(gè)位置都這么做一遍,就得到了兩個(gè)新個(gè)體(子代)。


但值得注意的是,如果是自然界,其實(shí)更優(yōu)秀的個(gè)體會(huì)擁有更大的繁殖機(jī)會(huì)。所以,我們可以使用一種叫輪盤(pán)賭的隨機(jī)選擇方式,代替之前的純隨機(jī)選擇。這樣,就可以讓適應(yīng)度更高的個(gè)體有更大機(jī)會(huì)變成父本,但也保留弱小個(gè)體被選中的可能。


以上圖藍(lán)色段被選中的機(jī)會(huì)為例,原本它應(yīng)當(dāng)為0.4,也就是生成一個(gè)0~1的隨機(jī)數(shù),如果隨機(jī)數(shù)的值小于0.4,那么藍(lán)色就被選中。

而轉(zhuǎn)化為輪盤(pán)賭后,藍(lán)色段的部分為0.227~0.59,也就是只有隨機(jī)值落在這個(gè)范圍內(nèi)時(shí),它才會(huì)被選中。如果是其它值,就留給其它段了。

可以明顯看出,這樣的選擇更照顧整體,原本大的值會(huì)有更大概率被選中,但小的也有機(jī)會(huì)。代碼實(shí)現(xiàn)也非常簡(jiǎn)單:

//計(jì)算輪盤(pán)賭概率分布 privatevoidCalcRouletteWheel() {     floattotalFitness=0f;     for (inti=0; i < parents.Length; i++)     {         totalFitness += parents[i].fitness;     }     floatcumulativeSum=0f;     for (inti=0; i < cumulativeProbabilities.Length; i++)     {         cumulativeSum += (parents[i].fitness / totalFitness);         cumulativeProbabilities[i] = cumulativeSum;     } } //輪盤(pán)賭隨機(jī)下標(biāo) privateintGetRouletteRandom() {     floatrand= Random.value;     // 選擇個(gè)體     for (inti=0; i < cumulativeProbabilities.Length; i++)     {         if (rand < cumulativeProbabilities[i])         {             return i;         }     }     // 如果沒(méi)有找到,返回最后一個(gè)個(gè)體(通常不會(huì)發(fā)生)     return cumulativeProbabilities.Length - 1; }

現(xiàn)在還有一個(gè)問(wèn)題,僅僅只是交叉互換,那么最終得到的最優(yōu)個(gè)體也只會(huì)囿于初始種群。如果初始種群中無(wú)論怎么交叉互換都無(wú)法得到優(yōu)良個(gè)體又該怎么辦?這時(shí)就得靠變異了。

變異的手段并不固定,只要能做到突破就可以。我的做法就是在原本數(shù)值的基礎(chǔ)上隨機(jī)增減一個(gè)小數(shù)值。但變異通常不能太頻繁發(fā)生,我們要為它規(guī)定一個(gè)較小的概率,否則大規(guī)模的變異反而會(huì)破壞優(yōu)良父本的傳承。

變異的發(fā)生可以與繁殖放在一起:

private voidGetChild() {     int p1, p2;     for(inti=0; i < parents.Length; i += 2)     {         p2 = p1 = GetRouletteRandom();         varcurWB= parents[i].WB;         while(p1 == p2 && parents.Length > 1)         {             p2 = GetRouletteRandom();         }         for(intj=0; j < curWB.Length; ++j)         {             varcurW= curWB[j].weights;             for (intk=0; k < curW.Length; ++k)             {                 if(Random.value < 0.5)                 {                     children[i].WB[j].weights[k] = parents[p2].WB[j].weights[k];                     if (i + 1 < children.Length)                     {                         children[i + 1].WB[j].weights[k] = parents[p1].WB[j].weights[k];                     }                 }                 else                 {                     children[i].WB[j].weights[k] = parents[p1].WB[j].weights[k];                     if (i + 1 < children.Length)                     {                         children[i + 1].WB[j].weights[k] = parents[p2].WB[j].weights[k];                     }                 }                 if (Random.value < mutationRate) //隨機(jī)變異,mutationRate為變異率                 {                     //mutationScale為變異的幅度,即變異帶來(lái)的數(shù)值增減幅度                     children[i].WB[j].weights[k] += Random.Range(-mutationScale, mutationScale);                 }                 if (i + 1 < children.Length && Random.value < mutationRate)                 {                     children[i + 1].WB[j].weights[k] += Random.Range(-mutationScale, mutationScale);                 }             }             varcurB= curWB[j].bias;             for (intk=0; k < curB.Length; ++k)             {                 if(Random.value < 0.5)                 {                     children[i].WB[j].bias[k] = parents[p2].WB[j].bias[k];                     if (i + 1 < children.Length)                     {                         children[i + 1].WB[j].bias[k] = parents[p1].WB[j].bias[k];                     }                 }                 else                 {                     children[i].WB[j].bias[k] = parents[p1].WB[j].bias[k];                     if (i + 1 < children.Length)                     {                         children[i + 1].WB[j].bias[k] = parents[p2].WB[j].bias[k];                     }                 }                 if (Random.value < mutationRate) //隨機(jī)變異,mutationRate為變異率                 {                     //mutationScale為變異的幅度,即變異帶來(lái)的數(shù)值增減幅度                     children[i].WB[j].bias[k] += Random.Range(-mutationScale, mutationScale);                 }                 if (i + 1 < children.Length && Random.value < mutationRate)                 {                     children[i + 1].WB[j].bias[k] += Random.Range(-mutationScale, mutationScale);                 }             }         }     } }

4. 優(yōu)勝劣汰

在繁殖得到新的一批子代后,我們將這些子代也進(jìn)行一次競(jìng)爭(zhēng),這樣所有的父代、子代就都有各自的適應(yīng)度了。我們將它們一起根據(jù)適應(yīng)度進(jìn)行排序,顯然,如果父代的數(shù)量是N,那么總共就有2N個(gè)個(gè)體。在排序后我們選擇前N個(gè)個(gè)體作為本輪的優(yōu)勝者,也是下輪的新父本。

//在父代和子代組成的整體中選出適應(yīng)度高的新父代 privatevoidGetBest() {     for(inti=0; i < totalPopulation.Length; ++i)     {         if (i < AllPopulation)             totalPopulation[i] = parents[i];         else             totalPopulation[i] = children[i - AllPopulation];     }     Array.Sort(totalPopulation, (a, b) => b.fitness.CompareTo(a.fitness)); }

也就是說(shuō),有更高適應(yīng)度的個(gè)體能存活下來(lái),其它的就被淘汰。而這些存活下來(lái)的個(gè)體會(huì)不斷重復(fù)這個(gè)過(guò)程。在數(shù)次迭代后,我們就一定可以得到理想中的個(gè)體(比如適應(yīng)度超高的那種)。這時(shí),我們就可以結(jié)束算法了。

三、實(shí)例:賽道小球

用一個(gè)比較簡(jiǎn)單的實(shí)例,串一遍整個(gè)過(guò)程。我們將訓(xùn)練一個(gè)用來(lái)跑賽道的小球。

1. 創(chuàng)建神經(jīng)網(wǎng)絡(luò)

在我的實(shí)現(xiàn)中,已將網(wǎng)絡(luò)結(jié)構(gòu)以ScriptObject形式存儲(chǔ),我們先新建一個(gè),在Project下右鍵Create/ANN/WeightAngBias:


然后設(shè)置具體結(jié)構(gòu),這次要完成的工作比較簡(jiǎn)單,就是訓(xùn)練一個(gè)可以繞圈跑的小球,所以網(wǎng)絡(luò)結(jié)構(gòu)比較簡(jiǎn)單。兩個(gè)隱藏層足矣(對(duì)應(yīng)Wei Bias Array的兩個(gè)元素),這個(gè)神經(jīng)網(wǎng)絡(luò)接受三個(gè)輸入,輸出兩個(gè)數(shù)據(jù)。


至于中間其它參數(shù)的設(shè)計(jì)要符合神經(jīng)網(wǎng)絡(luò)的結(jié)構(gòu),具體來(lái)說(shuō)就是:每一層的Weights數(shù)量要等于InputCount * OutputCount;除了第一層外,其它層的InputCount要等于上一層的OutputCount。(如果你對(duì)神經(jīng)網(wǎng)絡(luò)有所了解,那就能理解這些。)

Affine固定使用同名的Compute Shader,至于Activate Func和Loss Func其實(shí)可以不管,因?yàn)檫z傳算法訓(xùn)練用不著。

2. 創(chuàng)建遺傳個(gè)體

場(chǎng)景中已有一個(gè)球形物體,掛載了繼承GAUnit的Car腳本。


神經(jīng)網(wǎng)絡(luò)的3個(gè)輸入數(shù)據(jù)就來(lái)自小球的三條射線檢測(cè):

private voidCheckEnv() {     totalSensor = 0;     for(inti=0; i < direactions.Length; ++i)     {         vardir= transform.TransformDirection(direactions[i]);         if(Physics.Raycast(transform.position, dir, out RaycastHit hit,              rayLength[i], hitMask, QueryTriggerInteraction.Ignore))         {             inputVal[i] = hit.distance / rayLength[i];         }         else         {             inputVal[i] = 1;         }         totalSensor += inputVal[i];     } }

神經(jīng)網(wǎng)絡(luò)的兩個(gè)輸出分別用來(lái)控制,移動(dòng)速度以及角位移:

private void RunMLP() {     myMLP.Predict(inputVal);     moveVel = transform.TransformDirection(new Vector3( 0, 0, myMLP.outputData[0] * 10));     moveVel = Vector3.MoveTowards(rb.velocity, moveVel, 0.02f);     rb.velocity = moveVel;     transform.eulerAngles += new Vector3(0, myMLP.outputData[1] * 90 * Time.fixedDeltaTime, 0); }

我們還需要設(shè)計(jì)一個(gè)衡量適應(yīng)度的函數(shù)。而因?yàn)槲覀兇蛩阌?xùn)練一個(gè)能在賽道正中央前進(jìn)的小球,所以這里主要考慮「位移距離、速度、檢測(cè)距離」以及「是否有碰到墻」。一旦isOver為true后,GA會(huì)讓小球回到起始點(diǎn),進(jìn)行新的訓(xùn)練。

private voidCalculateFitness() {     totalMoveDis += Vector3.Distance(transform.position, lastPos);     avgSpeed = totalMoveDis / runningTime;     //適應(yīng)度與位移距離、速度、檢測(cè)距離有關(guān)     FitNess = (totalMoveDis*distanceMultipler) + (avgSpeed*avgSpeedMultiplier) + ( totalSensor / inputVal.Length *sensorMultiplier);     if (runningTime > 20 && FitNess < 40) //存活足夠時(shí)間且適應(yīng)度不低時(shí),結(jié)束本輪     {         isOver = true;     }     if(FitNess >= 1000) //適應(yīng)度很高時(shí),直接算成功,結(jié)束     {         isOver = true;     } } privatevoidOnCollisionEnter(Collision other) {     if(!isOver && hitMask.ContainLayer(other.gameObject.layer))     {         isOver = true; //碰到墻上,直接結(jié)束         rb.velocity = Vector3.zero;     } }

這樣,個(gè)體的設(shè)置就搞定了,它將作為訓(xùn)練時(shí)的運(yùn)行個(gè)體。

3. 遺傳算法訓(xùn)練器

在場(chǎng)景中任意激活的物體上,掛載GA腳本,并將Car拖拽在指定位置:


這個(gè)腳本中All Population是初始化種群的數(shù)量,這里填50。但注意,這并不會(huì)讓場(chǎng)景中出現(xiàn)50個(gè)小球,而是每輪小球得重復(fù)50次來(lái)逐一嘗試種群中的個(gè)體。Mutation Rate是變異率,這里填0.3;Mutation Scale是變異幅度默認(rèn)為1即可。

至于綠色框內(nèi)的,Is End Train用來(lái)結(jié)束遺傳算法的訓(xùn)練,并將最好的結(jié)果保存到先前的ScriptObject中。其余只是用來(lái)觀察小球當(dāng)前訓(xùn)練情況而已。

一切就緒后,點(diǎn)擊運(yùn)行即可訓(xùn)練。訓(xùn)練時(shí)我們可以調(diào)整Project Settings/Time/Time Scale加速訓(xùn)練。

需要注意的是,當(dāng)你想測(cè)試小球時(shí),一定要關(guān)閉GA腳本,或者將Train Unit置空,否則一運(yùn)行就會(huì)又重新訓(xùn)練Train Unit中的個(gè)體。比如這里,花了4分鐘訓(xùn)練出了一個(gè)能走圈的小球,保存訓(xùn)練結(jié)果,就要先勾上Is End Train,再終止運(yùn)行,而后取消啟用GA;這時(shí)再運(yùn)行,會(huì)發(fā)現(xiàn)小球可以自動(dòng)繞圈走了:


四、尾聲

完整的訓(xùn)練視頻在項(xiàng)目中有,如果了解神經(jīng)網(wǎng)絡(luò),或許這篇就好看懂些。大伙感興趣就嘗試下項(xiàng)目吧,也可以嘗試更復(fù)雜的賽道,更龐大的網(wǎng)絡(luò)。

文末,再次感謝狐王駕虎 的分享, 作者主頁(yè):https://home.cnblogs.com/u/OwlCat, 如果您有任何獨(dú)到的見(jiàn)解或者發(fā)現(xiàn)也歡迎聯(lián)系我們,一起探討。(QQ群: 793972859 )。

近期精彩回顧

【學(xué)堂上新】

【厚積薄發(fā)】

【學(xué)堂上新】

【厚積薄發(fā)】

特別聲明:以上內(nèi)容(如有圖片或視頻亦包括在內(nèi))為自媒體平臺(tái)“網(wǎng)易號(hào)”用戶上傳并發(fā)布,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相關(guān)推薦
熱點(diǎn)推薦
襲擊我國(guó)人員后,該武裝組織遭我軍合成營(yíng)"教科書(shū)式"圍殲

襲擊我國(guó)人員后,該武裝組織遭我軍合成營(yíng)"教科書(shū)式"圍殲

小哥很OK
2026-01-05 11:07:02
突傳消息!毛戈平和妻子、姐姐等擬套現(xiàn)14億港元!“用于投資,改善個(gè)人生活等”

突傳消息!毛戈平和妻子、姐姐等擬套現(xiàn)14億港元!“用于投資,改善個(gè)人生活等”

海峽網(wǎng)
2026-01-08 09:09:01
“哥都禮共和國(guó)”宣布成立,并宣布脫離緬甸獨(dú)立

“哥都禮共和國(guó)”宣布成立,并宣布脫離緬甸獨(dú)立

曼谷陳大叔
2026-01-07 15:57:35
女子開(kāi)車碾壓草場(chǎng)后續(xù):揚(yáng)言撞死牧民,真實(shí)身份被扒,公司被牽連

女子開(kāi)車碾壓草場(chǎng)后續(xù):揚(yáng)言撞死牧民,真實(shí)身份被扒,公司被牽連

奇思妙想草葉君
2026-01-07 23:56:24
美國(guó)扣押一艘與委內(nèi)瑞拉有關(guān)、懸掛俄羅斯旗幟的石油運(yùn)輸船,外交部回應(yīng)

美國(guó)扣押一艘與委內(nèi)瑞拉有關(guān)、懸掛俄羅斯旗幟的石油運(yùn)輸船,外交部回應(yīng)

環(huán)球網(wǎng)資訊
2026-01-08 15:38:17
油輪被扣押,俄議員呼喊“對(duì)美開(kāi)戰(zhàn)”

油輪被扣押,俄議員呼喊“對(duì)美開(kāi)戰(zhàn)”

跟著老李看世界
2026-01-08 08:57:52
上海通報(bào):公職人員沈劍被查,涉嫌嚴(yán)重違紀(jì)違法

上海通報(bào):公職人員沈劍被查,涉嫌嚴(yán)重違紀(jì)違法

上觀新聞
2026-01-08 12:10:08
朝鮮不會(huì)成為第二個(gè)委內(nèi)瑞拉!因?yàn)槌r有兩個(gè)后盾

朝鮮不會(huì)成為第二個(gè)委內(nèi)瑞拉!因?yàn)槌r有兩個(gè)后盾

米君文史
2026-01-07 10:01:47
李慧瓊當(dāng)選香港特別行政區(qū)第八屆立法會(huì)主席

李慧瓊當(dāng)選香港特別行政區(qū)第八屆立法會(huì)主席

界面新聞
2026-01-08 12:17:34
收評(píng):創(chuàng)業(yè)板指震蕩調(diào)整跌0.82% 全市場(chǎng)超百股漲停

收評(píng):創(chuàng)業(yè)板指震蕩調(diào)整跌0.82% 全市場(chǎng)超百股漲停

財(cái)聯(lián)社
2026-01-08 15:02:07
外交部:美方在公海海域隨意扣押他國(guó)船只嚴(yán)重違反國(guó)際法

外交部:美方在公海海域隨意扣押他國(guó)船只嚴(yán)重違反國(guó)際法

澎湃新聞
2026-01-08 15:36:26
景德鎮(zhèn)一家三口被撞亡案將宣判,代理律師發(fā)聲!家屬要求嚴(yán)懲

景德鎮(zhèn)一家三口被撞亡案將宣判,代理律師發(fā)聲!家屬要求嚴(yán)懲

南方都市報(bào)
2026-01-08 15:11:05
瓦良格號(hào)送到中國(guó)后有多震撼?專家刮掉表面的銹跡:鋼材品質(zhì)極佳

瓦良格號(hào)送到中國(guó)后有多震撼?專家刮掉表面的銹跡:鋼材品質(zhì)極佳

古書(shū)記史
2026-01-06 16:31:56
新華社官宣:轟-20和殲-36的正式亮相非常值得期待

新華社官宣:轟-20和殲-36的正式亮相非常值得期待

烽火觀天下
2026-01-08 11:52:17
鄭州9歲女孩課堂上寫(xiě)試卷時(shí)昏倒去世,家屬不忍尸檢“她怕疼”,當(dāng)?shù)爻闪0嗾{(diào)查

鄭州9歲女孩課堂上寫(xiě)試卷時(shí)昏倒去世,家屬不忍尸檢“她怕疼”,當(dāng)?shù)爻闪0嗾{(diào)查

大風(fēng)新聞
2026-01-08 14:41:04
72%煙草倒掛逼哭零售戶!寧可不訂也不賠錢(qián),市場(chǎng)根基正在爛根

72%煙草倒掛逼哭零售戶!寧可不訂也不賠錢(qián),市場(chǎng)根基正在爛根

老特有話說(shuō)
2026-01-07 00:40:03
女大學(xué)生餐館訛錢(qián)后續(xù):正臉曝光很漂亮 家人輪番找店主 目的曝光

女大學(xué)生餐館訛錢(qián)后續(xù):正臉曝光很漂亮 家人輪番找店主 目的曝光

鋭娛之樂(lè)
2026-01-08 08:34:40
微信辟謠網(wǎng)傳新規(guī)則

微信辟謠網(wǎng)傳新規(guī)則

界面新聞
2026-01-08 14:53:45
2025年的中國(guó)車市,教會(huì)了合資車企如何生存

2025年的中國(guó)車市,教會(huì)了合資車企如何生存

汽車公社
2026-01-08 08:33:54
雷軍全面回應(yīng)“營(yíng)銷大師”標(biāo)簽:娛樂(lè)節(jié)目中劉強(qiáng)東團(tuán)隊(duì)開(kāi)個(gè)玩笑,被人放大利用,現(xiàn)在聽(tīng)到營(yíng)銷兩個(gè)字都有點(diǎn)惡心

雷軍全面回應(yīng)“營(yíng)銷大師”標(biāo)簽:娛樂(lè)節(jié)目中劉強(qiáng)東團(tuán)隊(duì)開(kāi)個(gè)玩笑,被人放大利用,現(xiàn)在聽(tīng)到營(yíng)銷兩個(gè)字都有點(diǎn)惡心

每日經(jīng)濟(jì)新聞
2026-01-08 00:48:20
2026-01-08 16:28:49
侑虎科技UWA incentive-icons
侑虎科技UWA
游戲/VR性能優(yōu)化平臺(tái)
1537文章數(shù) 986關(guān)注度
往期回顧 全部

科技要聞

智譜拿下“全球大模型第一股”,憑什么

頭條要聞

中方被指正考慮進(jìn)一步收緊中重稀土出口 日本業(yè)界慌了

頭條要聞

中方被指正考慮進(jìn)一步收緊中重稀土出口 日本業(yè)界慌了

體育要聞

約基奇倒下后,一位故人邪魅一笑

娛樂(lè)要聞

2026春節(jié)檔將有六部電影強(qiáng)勢(shì)上映

財(cái)經(jīng)要聞

微軟CTO韋青:未來(lái)人類會(huì)花錢(qián)"戒手機(jī)"

汽車要聞

從量變到"智"變 吉利在CES打出了五張牌

態(tài)度原創(chuàng)

本地
手機(jī)
數(shù)碼
房產(chǎn)
軍事航空

本地新聞

1986-2026,一通電話的時(shí)空旅程

手機(jī)要聞

華為Pura X2曝光:翻書(shū)式橫向折疊,外屏尺寸增大

數(shù)碼要聞

鷹角網(wǎng)絡(luò)與八位堂聯(lián)名推出Retro 87復(fù)古鍵盤(pán)新春套裝,售價(jià)499元

房產(chǎn)要聞

三亞新房,又全國(guó)第一了!

軍事要聞

特朗普提出將美國(guó)軍費(fèi)提升至1.5萬(wàn)億美元

無(wú)障礙瀏覽 進(jìn)入關(guān)懷版