首頁 >後端開發 >Python教學 >一次彩票探索如何讓我了解 PyTorch 的強大功能

一次彩票探索如何讓我了解 PyTorch 的強大功能

Linda Hamilton
Linda Hamilton原創
2025-01-01 04:19:16648瀏覽

介紹

在某個時間點,您可能聽說過中獎彩票的機會非常渺茫。就像所有與機率相關的事情一樣,多次試驗可能會導致結果對你有利。現在,如果你參加很多次彩票,你中獎的機會會更大一些,這取決於你參加了多少次彩票。這仍然不能保證你最終會中獎,但是是均勻分佈的,並根據大數定律(在本例中意味著大量彩票),我們可以得出相對更有可能的可能性。

重要的是要了解,每個新彩票都是獨立於其他彩票的,並且相同的彩票“彩票號碼”可以贏得許多不同的彩票(遵循大數定律)。您也可能會運氣不好,無論您嘗試了多少次,每次都選錯了號碼。您現在有兩個選擇:

  1. 您每次都可以嘗試隨機數字。
  2. 您每次都可以嘗試相同號碼。

理論上(和數學上),這兩種情況發生的可能性相同。然而,場景 2 會帶給你輕微的優勢。隨著次數接近無窮大,最終每一個數字都會被選中。問題是,對於場景 1,您需要嘗試更多次,希望您當時選擇的數字與獲勝的數字相符。在情境 2 中,您確信隨著試驗趨於無限,您的數字將在某個時刻「獲勝」。對於本博文,我們將使用場景 2。

那麼,在我告訴你答案之前,你認為你能回答這個問題嗎?

「如果您周圍的所有彩票都有正好100 萬人的老虎機,並且您為每個玩過的人都選擇了同一張彩票[x],那麼您需要玩多少張彩票才能最終成為中獎者?

答案是...


How a Lottery Quest Led Me to The Powers of PyTorch

1440萬次

這篇文章的其餘部分將介紹我如何得出該值、如何進行模擬以及一些注意事項。從這裡開始事情會變得更加技術化。


How a Lottery Quest Led Me to The Powers of PyTorch

邏輯

100萬人的彩券號碼範圍為1 - 1,000,000(或0 - 999,999)。玩家每次抽獎只能選擇該範圍內的號碼,中獎彩券也只能來自該範圍。本質上,我們可以說我們將擁有一組 100 萬個數字。

考慮到使用者可以選擇該範圍內的任何數字,我們需要滿足集合中的每個項目至少被擊中一次的條件。這是因為,如果每個號碼至少被叫過一次,那麼它將涵蓋玩家可能選擇的任何可能的票號。這也意味著我們不關心每個數字運行了多少次,從而使「集合」成為用於我們的模擬的理想 Python 資料結構。我們將從一個空集合開始,並在每次迭代時用隨機生成的數字填充它,直到該集包含指定範圍內的每個數字。由於 Python 集合不重複數字,因此我們不必擔心確保唯一性。

def calculate_lottery_chances(lottery_players_count):
  number_set = set()
  count = 0

  while len(number_set) < lottery_players_count:
    gen_number = random.randint(1, lottery_players_count)
    number_set.add(gen_number)
    count += 1

  return count

對於 1,000,000 人的彩票,函數調用如下:calculate_lottery_chances(1000000),它將返回中獎之前嘗試彩票的次數。以這種方式排列程式碼使其具有很強的可擴展性。

How a Lottery Quest Led Me to The Powers of PyTorch

問題

簡單來說,問題的根源就是「變異」。第一次運行該函數時,我得到了“1310 萬”次作為我的值。我重新運行了一下,得到了大約 1390 萬的結果。我這樣做了更多次,得到的答案差異很大——在某個時候,我得到了 1500 萬個。很明顯,我需要這樣做並找到平均值。按照目前現有的模式,我認為隨著平均迭代次數趨於無窮大,我將更接近得到一個可靠的答案。需要一些可以做到這一點並且快速完成的東西,這促使我編寫了這個函數:

def average_over_n_times(function, function_arg, n):
  """
  This returns the average of the returned value of a function
  when it is called n times, with its (one) arg
  """
  total = 0
  for x in range(0, n):
    total += function(function_arg)

  return round(total/n)

隨後,所有內容都會被修補為:

num_of_trials = average_over_n_times(calculate_lottery_chances, lottery_players_count, n)

其中「n」表示結果平均的次數。然而,這帶來了另一個問題,我們將在下一節中討論。

「n」應該是什麼?

n 的值越大,結果越接近「平均情況」。然而,考慮到仍然沒有絕對性或確定性,執行這一系列任務太多次就會失去生產力。我這麼說有以下原因:

  • 時間不是無限的,我們不能無限期地執行這些計算,這意味著每次運行時總會有變化(無論多小),這違背了「絕對」的想法。
  • 計算資源是有限的。
  • 這個實驗的假設之一是電腦產生的「隨機性」可以準確地模擬現實。
  • 就像演算法運行時一樣,較小的幅度不再與較大的幅度一樣重要。當處理大於 13,000,000 的值時,大約 100,000 的變化就不會那麼顯著。

牢記這些,我用以下值測試了「n」:10、20、30、50、100、1000 和 5000 次。

PyTorch 從何而來?

此時,您可能想知道為什麼部落格標題中沒有提到「PyTorch」一詞。好吧,雖然我提到用不同的值測試 n,但它與我用於所有測試的程式碼並不相同。

這些都是計算量很大的實驗,我的 CPU 跟我說了一句話。我之前分享的程式碼片段是在一個具有零外部包依賴性的文件中編寫的,並且該文件在 bash shell 中運行,並在前面添加了 time 命令來追蹤執行時間。以下是僅使用 CPU 時的執行時間:

n Time (min and sec)
10 1m34.494s
20 3m2.591s
30 5m19.903s
50 10m58.844s
100 14m56.157s

在 1000 時,我無法再讓程式運作了。我不確定是不是中途斷了沒能停止執行,但我在4小時57分鐘後取消了。我認為有幾個因素影響了這一點,我將在「注意事項」部分中討論這些因素。不管怎樣,我的風扇噪音很刺耳,我知道我可能已經把筆記型電腦功率適中的 CPU 推得有點太多了。我拒絕接受失敗,在思考如何至少運行 4 位元迭代時,我想起了一位使用 PyTorch 的朋友告訴我的話:

「GPU 在運算密集方面通常比 CPU 更有效率」

PyTorch 使用 GPU,使其成為完成這項工作的完美工具。

重構

PyTorch 將用於我們目的的計算,因此重構現有的calculate_lottery_chances() 程式碼意味著更改依賴CPU 的數值運算並切換到適當的PyTorch 資料結構。簡而言之:

  • Python set() 資料型別將不再足夠。
  • Python randint() 函數將替換為其 PyTorch 等效函數。
  • 由於 set() 資料類型不夠,因此會切換為產生與 lottery_players_count 大小相符的零張量,並用布林值來指示某個號碼之前是否中獎。

calculate_lottery_chances 的重構如下:

def calculate_lottery_chances(lottery_players_count):
  number_set = set()
  count = 0

  while len(number_set) < lottery_players_count:
    gen_number = random.randint(1, lottery_players_count)
    number_set.add(gen_number)
    count += 1

  return count

我將裝置設定為“xpu”,因為我的電腦使用 PyTorch 支援的 Intel Graphics GPU。

輸出

為了確保在執行過程中使用我的 GPU,我在運行之前打開了 Windows 工作管理員並導航到「效能」部分。運行時,我發現 GPU 資源使用量有明顯峰值。
對於上下文,這是之前和之後的對比:

之前:

How a Lottery Quest Led Me to The Powers of PyTorch
請注意 GPU 使用率為 1%

之後:

How a Lottery Quest Led Me to The Powers of PyTorch
請注意,GPU 使用率為 49%

對於不同 n 值的運行時間,GPU 的速度要快幾倍。它在不到一分鐘的時間內始終運行低於 100 的 n 值,並且能夠計算 5000(五千!)

的 n 值

這是使用 GPU 的執行時間表:

n Time (min and sec)
10 0m13.920s
20 0m18.797s
30 0m24.749s
50 0m34.076s
100 1m12.726s
1000 16m9.831s

為了直觀地了解本實驗中 GPU 和 CPU 操作之間的效能差距有多大,可以考慮以下資料視覺化:

How a Lottery Quest Led Me to The Powers of PyTorch

x 軸的上限為 100,因為我無法再從 CPU 獲得實際的「及時」輸出,因此沒有空間與 GPU 進行比較。使用 1000 - 5000 範圍內的數字進行實驗,結果往往是「1440 萬次」。這就是我之前得到答案的方式。

注意事項

這個實驗做出了假設並依賴某些做事方式。此外,我對 PyTorch 的經驗不足可能意味著可能有更有效的方法。以下是一些需要考慮的因素可能影響了我的發現的準確性或執行時間:

  1. 我做了一個微妙的假設,即電腦生成的隨機性模仿了現實生活(物理世界)中的隨機性。
  2. 雖然我切換了一些邏輯以使用 PyTorch,但其餘程式碼仍然依賴 CPU。例如,在 Average_over_n_times() 函數中,迴圈中的加法和求平均值可能都會受益於 PyTorch 的等效項。我懷疑性能會有所提升。
  3. 我不確定我使用的batch_size對準確性和效能的影響。
  4. 所有 CPU 和 GPU 測試都是在我的電腦接通電源的情況下完成的,以便讓機器發揮最佳狀態。使用電池供電的設備運行它們可能會獲得更長的運行時間。
  5. PyTorch 的 CUDA 可能比「XPU」更有優勢,但我的電腦不支援前者。
  6. 測試期間我避免讓我的電腦「休眠」。如果您的電腦處於睡眠狀態,測試可能需要更長時間才能運作。

最後,我想指出,這是我第一次使用 PyTorch 做任何事,它的性能給我留下了深刻的印象。

結論

當我陷入困境時,我沒想到會看到效能上的如此提升。我了解了張量背後的想法以及一些有關計算更複雜的任務背後的支援機制的知識。您可以隨意使用、複製或修改程式碼片段。

感謝您對我的包容,希望您閱讀愉快。

下次再見,

乾杯。 ?

以上是一次彩票探索如何讓我了解 PyTorch 的強大功能的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn