強化學習(第三課第三周)

文章目錄

    • 強化學習(第三課第三周)
      • 一、以火星探測器為例說明強化學習的形式化表示
      • 二、強化學習中的回報
      • 三、強化學習算法的目標
        • (一)馬爾可夫決策過程
        • (二)狀態動作價值函數
        • (四)使用Bellman方程幫助我們計算狀態動作價值函數
      • 三、連續狀態空間的應用示例(以月球著陸器為示例)
        • (一)月球著陸器的前提信息
        • (二)訓練一個神經網絡來計算或者近似狀態動作價值函數
        • (三)優化DQN算法
          • 1、優化神經網絡結構
          • 2、epsilon貪婪策略
          • 3、小批量處理及軟更新
      • 四、Deep Q-Learning Algorithm with Experience Replay(代碼版)

強化學習(第三課第三周)

強化學習:找到當前狀態s到動作y的映射函數。強化學習的關鍵輸入是獎勵或者獎勵函數,讓模型多做一些有獎勵的行為,少做一些有懲罰的行為,這樣以后算法會自動找出如何選擇好的行動。

一、以火星探測器為例說明強化學習的形式化表示

在這里插入圖片描述

如上圖所示,強化學習包含了四個要素,分別是當前狀態、動作、獎勵(與當前狀態相關)、下一狀態。強化學習如何運行停止呢,一般是有一個終止狀態。

二、強化學習中的回報

在上面的獎勵里面,我們會為每一個獎勵添加折現因子(一個接近1的數),它的作用是讓強化學習變得急功近利,即越早得到獎勵,總回報值越高。示例如下;

在這里插入圖片描述

總之,我們的回報與動作息息相關,采取不同的動作,回報也會有所差別,回報是系統獲得獎勵的總和,示例如下:在這里插入圖片描述

對于負獎勵而言,算法更偏向于將負獎勵推向未來,這樣會盡量小幅度減少我們的回報值。

三、強化學習算法的目標

下面的講解都是根據火星探測器(離散狀態)的示例進行的。

(一)馬爾可夫決策過程

我們的目標是提出一個稱為pi的函數:它是將任何狀態作為輸入并映射到它想讓我們采取的的行動a上面。這個函數會應用于狀態s,并且告訴我們在那個狀態我們需要采取什么行動,以便最大化回報。

強化學習可以在很多方面進行應用:馬爾可夫決策過程(MDP)。
在這里插入圖片描述

(二)狀態動作價值函數

狀態動作價值函數(Q),報告了如果你在狀態s采取動作a然后表現最優的回報。計算示例如下:
在這里插入圖片描述

如果我們能夠計算出每個狀態和每個行動的狀態動作價值函數值Q(s,a),那么這就給了我們一種計算最優策略pi(s)的好方法。

我們只需要計算出每個狀態動作的Q值,選擇該狀態Q值最大的那個動作,就是我們的最優動作;示例如下:
在這里插入圖片描述

(四)使用Bellman方程幫助我們計算狀態動作價值函數

貝爾曼方程如下:通過示例證明貝爾曼方程確實可以正確計算出狀態動作價值函數

在這里插入圖片描述

注意:當狀態s為終端狀態時,貝爾曼方程沒有第二項,因為沒有下一個狀態了。

Q(s,a)的定義假設我們之后會最優地行動。所以貝爾曼方程地第二項是下一個狀態的最優回報。

由于強化學習的過程具有很多隨機性,受環境的影響,最終機器的動作路徑可能不是按照最優路徑進行的,所以我們感興趣的是最大化折扣獎勵總和的平均值。所以強化學習的任務就是選擇一個策略pi以最大化平均值或期望的總和。

在這里插入圖片描述

這里我理解的平均值就是:多次進行最優策略,相同的策略,但由于受到外界環境的影響,機器最終的動作路徑會有所不同,那么回報也會不同,我們需要做的是最優化這個回報的平均值。

三、連續狀態空間的應用示例(以月球著陸器為示例)

(一)月球著陸器的前提信息

在強化學習的應用中,也存在很多狀態是連續的,可能是一個狀態向量,向量里面的每一個數值都有一個范圍,這個數值就在這個范圍里面進行變化。

月球著陸器的狀態是一個向量,包含了很多信息,示例如下:
在這里插入圖片描述

根據不同的狀態信息有不同的獎勵措施:

在這里插入圖片描述

月球著陸器的折扣因子如下:
在這里插入圖片描述

根據上面的前提,我們需要設計一個強化學習算法,來使得月球著陸器在不同的狀態執行正確的動作,實現更好的著陸。

(二)訓練一個神經網絡來計算或者近似狀態動作價值函數

提供給神經網絡的輸入則是與月球著陸器的狀態和動作:狀態是一個包含了8個數值的列表,動作是進行獨熱編碼的4個數值,一共是12個數值。經過神經網咯,最終輸出的是該狀態動作的價值函數Q。這就叫做深度強化學習,我們將監督學習融入到了強化學習中去。具體如下:

在這里插入圖片描述

我們如何構造出關于輸入和輸出的訓練集供神經網絡學習呢?月球著陸模擬器,我們嘗試不同的狀態執行不同的動作,來得到訓練集。

示例如下:在這里插入圖片描述

深度Q網絡算法(DQN)的執行過程:

在這里插入圖片描述

中間特別需要注意的是,每一次訓練出來的新的Q,我們會把它將原來的Q替換掉,替換之后的數據集再次進行神經網絡訓練,這樣不斷迭代之后,Q函數會是一個很好的狀態動作價值估計。

(三)優化DQN算法
1、優化神經網絡結構

上面的模型訓練結束之后,我們想要得到Q值最大的那個動作作為最優策略,我們需要對當前狀態進行四次推理,才能得到。對上述算法的一個改進措施就是:訓練一個神經網絡來輸出當前狀態的四個Q值更為高效。示例如下:在這里插入圖片描述

2、epsilon貪婪策略

在我們完成算法學習之前,也就是在過程中,我們不知道某一個狀態的最佳動作是什么,算法還沒有對Q有一個很好的估計。

在我們獲取訓練集時,我們會隨機采取一些行動,但是為了使算法更好的學習,我們不能隨意地采取一些行動,因為那通常是一個糟糕的行動,所以我們在采取行動時,采取的是最大化Q(當前的Q)的一個動作,即使它可能現在還不是一個很好的估計,這是一個方式之一;

那么另外一種方式(貪婪策略)就是:大多數時候,我們嘗試使用當前的Q模型來估算選擇一個好的行動(貪婪),小部分時間隨機采取一個行動(探索)。

為什么要有一小部分隨機選擇呢,原因是神經網絡在學習時,由于什么奇怪的原因,可能一直都沒有選擇過某一個行動,盡管那個行動可能會表現得好,隨機值用來填補這一缺漏。貪婪策略指的是有epsilon*100%的數據是來自于隨機采取的行動。

隨著模型訓練的深入,我們可以逐漸減少隨機行動的比率,而更多地采取模型訓練之后的Q來進行行動的選擇。

在這里插入圖片描述

3、小批量處理及軟更新

在監督學習中,當樣本數量巨大時,我們每執行一次梯度下降,就會計算一次數億數據的一個平均值,這樣太過耗費時間和資源。小批量梯度下降的理念是每次迭代不適用全部數據樣本,我們可以取較少的樣本數。

在這里插入圖片描述

我們將原本的數據集劃分成若干個小的數據集,依次對這些小的數據集進行梯度下降,在梯度下降的過程中,參數逐漸擬合小數據集,直到擬合完所有的子數據集。雖然小樣本數據集在進行梯度下降是沒有大數據集那樣順滑,變得很曲折,但是計算資源卻會小很多。

在這里插入圖片描述

在強化學習中,同樣也可以如此:

在這里插入圖片描述

另外一種改進就是軟更新,它所解決的問題是:在用新的模型Q覆蓋舊的Q時,可能新的還沒有舊的好,我們該怎么辦呢?

我們可以控制舊Q向新Q更新的激進速度,來實現自我更新,使得強化學習算法能夠更快地收斂,使得強化學習算法不太可能出現動蕩、發散或者其他不良情況。通過使用軟更新,我們可以確保目標值 緩慢變化,這大大提高了我們學習算法的穩定性。

在這里插入圖片描述

四、Deep Q-Learning Algorithm with Experience Replay(代碼版)

構建網絡:

# UNQ_C1
# GRADED CELL# 創建主 Q 網絡,用于估計 Q(s, a) 值
q_network = Sequential([### START CODE HERE ### Input(shape=state_size),                    # 輸入層:維度等于狀態向量長度Dense(units=64, activation="relu"),         # 隱藏層 1:64 個 ReLU 神經元Dense(units=64, activation="relu"),         # 隱藏層 2:64 個 ReLU 神經元Dense(units=num_actions, activation="linear"),  # 輸出層:每個動作對應一個 Q 值,線性激活### END CODE HERE ### 
])# 創建目標 Q^- 網絡,用于計算目標 y 值(參數更新較主網絡慢)
target_q_network = Sequential([### START CODE HERE ### Input(shape=state_size),                    # 輸入層:維度同上Dense(units=64, activation="relu"),         # 隱藏層 1:64 個 ReLU 神經元Dense(units=64, activation="relu"),         # 隱藏層 2:64 個 ReLU 神經元Dense(units=num_actions, activation="linear"),  # 輸出層:每個動作對應一個 Q 值,線性激活### END CODE HERE ###
])# 創建優化器:使用 Adam,學習率由 ALPHA 指定
### START CODE HERE ### 
optimizer = Adam(learning_rate=ALPHA)           # 優化器將用于最小化 TD-error 損失
### END CODE HERE ###

經驗回放元組:

# 使用 collections.namedtuple 創建一個輕量級、不可變的數據結構
experience = namedtuple("Experience",                       # 新數據類型的名字,叫 Experiencefield_names=[                       # 指定每個實例里包含的字段名"state",        # 當前觀測/狀態 s_t"action",       # 在該狀態下采取的動作 a_t"reward",       # 環境返回的即時獎勵 r_t"next_state",   # 執行動作后進入的下一狀態 s_{t+1}"done"          # 布爾標志:True 表示回合結束,False 表示未結束]
)

構造損失函數:

def compute_loss(experiences, gamma, q_network, target_q_network):""" Calculates the loss.Args:experiences: (tuple) tuple of ["state", "action", "reward", "next_state", "done"] namedtuplesgamma: (float) The discount factor.q_network: (tf.keras.Sequential) Keras model for predicting the q_valuestarget_q_network: (tf.keras.Sequential) Karas model for predicting the targetsReturns:loss: (TensorFlow Tensor(shape=(0,), dtype=int32)) the Mean-Squared Error betweenthe y targets and the Q(s,a) values."""# 1. 把 experiences 這個批次的數據拆成五個張量states, actions, rewards, next_states, done_vals = experiences# 2. 用“目標網絡”計算下一狀態 s' 的最大 Q 值:max_a' Q?(s', a')#    axis=-1 表示在動作維度上取最大值max_qsa = tf.reduce_max(target_q_network(next_states), axis=-1)# 3. 計算 y 目標值:#    如果 done=1(回合結束),y = r#    否則 y = r + γ * max_a' Q?(s', a')y_targets = rewards + (gamma * max_qsa * (1 - done_vals))# 4. 用“主網絡”計算當前狀態-動作對應的 Q(s, a)q_values = q_network(states)                  # 形狀: [batch_size, num_actions]# 5. 從 Q(s,·) 里挑出實際被執行動作 a 對應的 Q(s,a)#    利用 gather_nd 按 (batch_index, action_index) 取值q_values = tf.gather_nd(q_values,tf.stack([tf.range(q_values.shape[0]),   # 每個樣本的 batch 索引tf.cast(actions, tf.int32)],    # 每個樣本的動作索引axis=1))# 6. 計算 MSE 損失: (y_targets - Q(s,a))^2 的均值loss = MSE(y_targets, q_values)# 7. 把標量損失返回給調用者return loss

更新網絡權重:

# 用 @tf.function 裝飾器將函數編譯為靜態圖,加快訓練速度并支持自動微分
@tf.function
def agent_learn(experiences, gamma):"""根據一批經驗更新 Q 網絡權重(主網絡 + 目標網絡)。Args:experiences: (tuple) 由 ["state", "action", "reward", "next_state", "done"] 五個字段組成的 namedtuple 批次gamma: (float) 折扣因子 γ"""# 1. 在 GradientTape 的上下文里計算損失,便于后續求梯度with tf.GradientTape() as tape:loss = compute_loss(experiences, gamma, q_network, target_q_network)# 2. 根據 loss 對主網絡所有可訓練變量求梯度gradients = tape.gradient(loss, q_network.trainable_variables)# 3. 將梯度應用到主網絡權重,完成一次梯度下降更新optimizer.apply_gradients(zip(gradients, q_network.trainable_variables))# 4. 用軟更新或硬更新策略,把主網絡權重同步/平滑到目標網絡utils.update_target_network(q_network, target_q_network)

訓練模型:

# ---------------- 計時開始 ----------------
start = time.time()# ---------------- 訓練超參數 ----------------
num_episodes = 2000               # 總共訓練多少回合(episode)
max_num_timesteps = 1000          # 每回合最多走多少步(超過也強制結束)total_point_history = []          # 記錄每回合得分的列表,用于計算滑動平均分num_p_av = 100                    # 計算最近多少回合的平均得分
epsilon = 1.0                     # ε-貪婪策略的初始探索率(完全隨機)# 創建經驗回放池(雙端隊列),容量 MEMORY_SIZE,滿時自動彈出最舊經驗
memory_buffer = deque(maxlen=MEMORY_SIZE)# 把主網絡(q_network)的權重一次性復制給目標網絡(target_q_network),保證初始同步
target_q_network.set_weights(q_network.get_weights())# ---------------- 主訓練循環 ----------------
for i in range(num_episodes):# 1. 重置環境,拿到初始狀態state = env.reset()total_points = 0          # 本回合累計得分# 2. 單回合內循環for t in range(max_num_timesteps):# 2-1 將狀態擴展成 batch=1 的形狀,喂給主網絡state_qn = np.expand_dims(state, axis=0)# 2-2 主網絡輸出每個動作的 Q 值q_values = q_network(state_qn)# 2-3 根據 ε-貪婪策略選擇動作action = utils.get_action(q_values, epsilon)# 2-4 在環境中執行動作,拿到下一步信息next_state, reward, done, _ = env.step(action)# 2-5 把五元組經驗存進回放池memory_buffer.append(experience(state, action, reward, next_state, done))# 2-6 判斷“是否到更新時機”:時間步滿足 + 回放池夠大update = utils.check_update_conditions(t, NUM_STEPS_FOR_UPDATE, memory_buffer)if update:# 2-6-1 從回放池隨機采樣一個 mini-batch 經驗experiences = utils.get_experiences(memory_buffer)# 2-6-2 用 DQN 算法更新主網絡權重agent_learn(experiences, GAMMA)# 2-7 狀態轉移,累加獎勵state = next_state.copy()total_points += reward# 2-8 如果回合結束,跳出內層循環if done:break# 3. 記錄本回合得分,計算最近 num_p_av 回合平均分total_point_history.append(total_points)av_latest_points = np.mean(total_point_history[-num_p_av:])# 4. 每回合遞減 ε(線性/指數衰減,函數內部實現)epsilon = utils.get_new_eps(epsilon)# 5. 實時打印進度(同一行覆蓋)print(f"\rEpisode {i+1} | Total point average of the last {num_p_av} episodes: {av_latest_points:.2f}", end="")# 6. 每 num_p_av 回合換行打印一次if (i+1) % num_p_av == 0:print(f"\rEpisode {i+1} | Total point average of the last {num_p_av} episodes: {av_latest_points:.2f}")# 7. 如果最近平均得分 ≥ 200,認為環境已解決if av_latest_points >= 200.0:print(f"\n\nEnvironment solved in {i+1} episodes!")q_network.save('lunar_lander_model.h5')   # 保存最終模型break# ---------------- 訓練結束,輸出總耗時 ----------------
tot_time = time.time() - start
print(f"\nTotal Runtime: {tot_time:.2f} s ({(tot_time/60):.2f} min)")

在深度Q學習(DQN)中,神經網絡訓練所需的數據來源于智能體與環境的交互過程。具體來說,數據生成和使用的流程如下:

  1. 數據生成(交互過程)

    - 智能體在環境中執行動作(基于當前策略,如ε-貪婪策略)。

    - 環境返回執行動作后的結果:新的狀態(next_state)、獎勵(reward)以及是否終止(done)。

    - 將每一步的交互結果存儲為一個五元組(state, action, reward, next_state, done),稱為一個經驗(experience)。

  2. 數據存儲(經驗回放池)

    - 這些經驗被存儲在一個固定大小的緩沖區中,稱為經驗回放池(experience replay buffer)。當緩沖區滿時,舊的經驗會被新的經驗覆蓋。

  3. 數據采樣(訓練數據來源)

    - 在訓練時,從經驗回放池中隨機采樣一批(mini-batch)經驗(例如,64個經驗樣本)。

    - 這個隨機采樣的過程打破了數據之間的相關性(因為相鄰的經驗是相關的),使得訓練更加穩定。

  4. 數據使用(訓練網絡)

    - 對于每個采樣的經驗樣本(s, a, r, s’, done):

? - 用主網絡(q_network)計算當前狀態s下所有動作的Q值,并選取執行動作a對應的Q值作為預測值(predicted Q)。

? - 用目標網絡(target_q_network)計算下一個狀態s’的最大Q值:max_a’ Q_target(s’, a’)。

? - 如果done為真(即終止狀態),則目標值(target)就是r;否則,目標值 = r + γ * max_a’ Q_target(s’, a’)。

- 通過最小化預測值(predicted Q)與目標值(target)之間的均方誤差來更新主網絡的參數。

總結:訓練數據來源于智能體在環境中探索得到的經驗,這些經驗被存儲在經驗回放池中,訓練時從中隨機采樣一批數據用于神經網絡的參數更新。這種機制使得數據可以被多次利用(提高樣本效率),并且通過隨機采樣減少了數據間的相關性,從而穩定了訓練過程。

結束!!!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/90606.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/90606.shtml
英文地址,請注明出處:http://en.pswp.cn/web/90606.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

星痕共鳴數據分析2

今天實驗內容是攻擊力部分 1.思路 由于昨天數據分析出了一個函數 這個函數可以把奇怪的字節變成正常的數字 int parse_varint(unsigned const char* data, int count) {int value 0;int shift 0;for (int i 0; i < count; i) {unsigned char byte data[i];value | ((byt…

強化學習新發現:僅需更新5%參數的稀疏子網絡可達到全模型更新效果

摘要&#xff1a;強化學習&#xff08;RL&#xff09;已成為大語言模型&#xff08;LLM&#xff09;在完成預訓練后與復雜任務及人類偏好對齊的關鍵步驟。人們通常認為&#xff0c;要通過 RL 微調獲得新的行為&#xff0c;就必須更新模型的大部分參數。本研究對這一假設提出了挑…

electron 使用記錄

目錄 代理設置以打包成功 參考文檔 代理設置以打包成功 參考文檔 使用 JavaScript、HTML 和 CSS 構建跨平臺桌面應用 |電子 --- Build cross-platform desktop apps with JavaScript, HTML, and CSS | Electron

Spring boot Grafana優秀的監控模板

JVM (Micrometer) | Grafana Labs 1 SLS JVM監控大盤 | Grafana Labs Spring Boot 2.1 Statistics | Grafana Labs springboot granfana 監控接口指定接口響應的 在Spring Boot應用中&#xff0c;使用Grafana進行監控通常涉及以下幾個步驟&#xff1a; 設置Prometheus作…

LeetCode11~30題解

LeetCode11.盛水最多的容器&#xff1a; 題目描述&#xff1a; 給定一個長度為 n 的整數數組 height 。有 n 條垂線&#xff0c;第 i 條線的兩個端點是 (i, 0) 和 (i, height[i]) 。 找出其中的兩條線&#xff0c;使得它們與 x 軸共同構成的容器可以容納最多的水。 返回容器…

計算機結構-邏輯門、存儲器、內存、加法器、鎖存器、程序計數器

邏輯門 邏輯門簡單地理解即通過特定的條件實現與、或、非、異或等相關邏輯二極管 這些最基礎的邏輯門都是通過電路元器件進行搭建的&#xff0c;即半導體材料搭建的二極管二極管有個特點&#xff0c;一定條件下才可以導通&#xff0c;即得接對正負極&#xff0c;具體的原理可以…

連鎖店鋪巡查二維碼的應用

在連鎖店鋪的運營管理中&#xff0c;巡查工作是保障各門店規范運作、提升服務質量的關鍵環節。巡查二維碼的出現&#xff0c;為這一環節帶來了高效、便捷且規范的解決方案&#xff0c;其應用場景廣泛&#xff0c;優勢顯著。在如今的繁雜且效果參差不齊電子二維碼市場中&#xf…

各種前端框架界面

前端技術更新迭代很快&#xff0c;已經有不少新的前端框架問世&#xff0c;而且像geeker-admin風格的界面設計也挺不錯的。 今天去面試了前端開發崗位&#xff0c;感覺希望不大。畢竟中間空了一段時間沒接觸&#xff0c;得趕緊把新的知識點補上&#xff0c;這樣哪怕是居家辦公也…

DApp 開發者 學習路線和規劃

目錄 ?? 一、學習路線圖 階段 1:基礎知識(1~2 周) 階段 2:智能合約開發(3~4 周) 階段 3:前端與區塊鏈交互(2~3 周) 階段 4:進階與生態系統(持續學習) ?? 二、學習規劃建議(3~4 個月) ?? 三、工具推薦 ?? 四、附加建議 ?? 一、學習路線圖 階段 …

數據結構 二叉樹(3)---層序遍歷二叉樹

在上篇文章中我們主要講了關于實現二叉樹的內容&#xff0c;包括遍歷二叉樹&#xff0c;以及統計二叉樹等內容。而在這篇文章中我們將詳細講解一下利用隊列的知識實現層序遍歷二叉樹。那么層序遍歷是什么&#xff1f;以及利用隊列遍歷二叉樹又是怎么遍歷的&#xff1f;下面讓我…

【橘子分布式】gRPC(番外篇-攔截器)

一、簡介 我們之前其實已經完成了關于grpc的一些基礎用法&#xff0c;實際上還有一些比較相對進階的使用方式。比如&#xff1a; 攔截器&#xff1a;包括客戶端和服務端的攔截器&#xff0c;進而在每一端都可以劃分為流式的攔截器和非流式的攔截器。和以前我們在spring web中的…

深入探索嵌入式仿真教學:以酒精測試儀實驗為例的高效學習實踐

引言&#xff1a;嵌入式技術普及下的教學革新 嵌入式系統作為現代科技的核心驅動力&#xff0c;其教學重要性日益凸顯。然而&#xff0c;傳統硬件實驗面臨設備成本高、維護難、時空受限等挑戰。如何突破這些瓶頸&#xff0c;實現高效、靈活、專業的嵌入式教學&#xff1f;本文將…

三種深度學習模型(GRU、CNN-GRU、貝葉斯優化的CNN-GRU/BO-CNN-GRU)對北半球光伏數據進行時間序列預測

代碼功能 該代碼實現了一個光伏發電量預測系統&#xff0c;采用三種深度學習模型&#xff08;GRU、CNN-GRU、貝葉斯優化的CNN-GRU/BO-CNN-GRU&#xff09;對北半球光伏數據進行時間序列預測對北半球光伏數據進行時間序列預測&#xff0c;并通過多維度評估指標和可視化對比模型性…

PostgreSQL對象權限管理

本文記述在postgreSQL中對用戶/角色操作庫、模式、表、序列、函數、存儲過程的權限管理針對數據庫的授權 授權&#xff1a;grant 權限 on database 數據庫 to 用戶/角色; 撤權&#xff1a;revoke 權限 on database 數據庫 from 用戶/角色; 針對模式的授權 授權&#xff1a;gran…

Wordpress主題配置

一、下載主題 主題下載地址&#xff1a;https://www.iztwp.com/tag/blog-theme 二、主題安裝 三、上傳主題安裝即可 四、安裝完成啟動主題

lock 和 synchronized 區別

1. 引言 在多線程編程中&#xff0c;我們經常需要確保某些代碼在同一時刻只由一個線程執行。這種機制通常叫做“互斥鎖”或“同步”。Java 提供了兩種主要的同步機制&#xff1a;synchronized 關鍵字和 Lock 接口。盡管它們的作用相似&#xff0c;都用于實現線程的同步&#xf…

Tkinter - Python圖形界面開發指南

作者&#xff1a;唐叔在學習 專欄&#xff1a;唐叔學python 標簽&#xff1a;Python GUI編程 Tkinter教程 圖形界面開發 Python實戰 界面設計 事件監聽 Python入門 唐叔Python 編程學習 軟件開發 文章目錄一、Tkinter是什么&#xff1f;為什么選擇它&#xff1f;二、Tkinter基礎…

Java基礎day15

目錄 一、Java集合簡介 1.什么是集合&#xff1f; 2.集合接口 3.小結 二、List集合 1.List集合簡介 三、ArrayList容器類 1.初始化 1.1無參初始化 1.2有參初始化 2.數據結構 3.常用方法 3.1增加元素 3.2查找元素 3.3 修改元素 3.4 刪除元素 3.5 其他方法 4.擴…

React Three Fiber 實現晝夜循環:從光照過渡到日月聯動的技術拆解

在 3D 場景中用 React Three Fiber 實現自然的晝夜循環&#xff0c;核心難點在于光照的平滑過渡、日月運動的聯動邏輯、晝夜狀態下的光影差異處理&#xff0c;以及性能與視覺效果的平衡。本文以一個 ReactThree.js 的實現為例&#xff0c;詳細解析如何通過三角函數計算日月位置…

進階向:基于Python的簡易屏幕畫筆工具

用Python打造你的專屬屏幕畫筆工具&#xff1a;零基礎也能輕松實現你是否曾在觀看網課或參加遠程會議時&#xff0c;想要直接在屏幕上標注重點&#xff1f;或者作為設計師&#xff0c;需要快速繪制創意草圖&#xff1f;現在&#xff0c;只需幾行Python代碼&#xff0c;你就能輕…