在某個時間點,您可能聽說過中獎彩票的機會非常渺茫。就像所有與機率相關的事情一樣,多次試驗可能會導致結果對你有利。現在,如果你參加很多次彩票,你中獎的機會會更大一些,這取決於你參加了多少次彩票。這仍然不能保證你最終會中獎,但是是均勻分佈的,並根據大數定律(在本例中意味著大量彩票),我們可以得出相對更有可能的可能性。
重要的是要了解,每個新彩票都是獨立於其他彩票的,並且相同的彩票“彩票號碼”可以贏得許多不同的彩票(遵循大數定律)。您也可能會運氣不好,無論您嘗試了多少次,每次都選錯了號碼。您現在有兩個選擇:
理論上(和數學上),這兩種情況發生的可能性相同。然而,場景 2 會帶給你輕微的優勢。隨著次數接近無窮大,最終每一個數字都會被選中。問題是,對於場景 1,您需要嘗試更多次,希望您當時選擇的數字與獲勝的數字相符。在情境 2 中,您確信隨著試驗趨於無限,您的數字將在某個時刻「獲勝」。對於本博文,我們將使用場景 2。
那麼,在我告訴你答案之前,你認為你能回答這個問題嗎?
「如果您周圍的所有彩票都有正好100 萬人的老虎機,並且您為每個玩過的人都選擇了同一張彩票[x],那麼您需要玩多少張彩票才能最終成為中獎者?
答案是...
1440萬次。
這篇文章的其餘部分將介紹我如何得出該值、如何進行模擬以及一些注意事項。從這裡開始事情會變得更加技術化。
考慮到使用者可以選擇該範圍內的任何數字,我們需要滿足集合中的每個項目至少被擊中一次的條件。這是因為,如果每個號碼至少被叫過一次,那麼它將涵蓋玩家可能選擇的任何可能的票號。這也意味著我們不關心每個數字運行了多少次,從而使「集合」成為用於我們的模擬的理想 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),它將返回中獎之前嘗試彩票的次數。以這種方式排列程式碼使其具有很強的可擴展性。
簡單來說,問題的根源就是「變異」。第一次運行該函數時,我得到了“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」:10、20、30、50、100、1000 和 5000 次。
此時,您可能想知道為什麼部落格標題中沒有提到「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 資料結構。簡而言之:
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 資源使用量有明顯峰值。
對於上下文,這是之前和之後的對比:
之前:
請注意 GPU 使用率為 1%
之後:
請注意,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 操作之間的效能差距有多大,可以考慮以下資料視覺化:
x 軸的上限為 100,因為我無法再從 CPU 獲得實際的「及時」輸出,因此沒有空間與 GPU 進行比較。使用 1000 - 5000 範圍內的數字進行實驗,結果往往是「1440 萬次」。這就是我之前得到答案的方式。
這個實驗做出了假設並依賴某些做事方式。此外,我對 PyTorch 的經驗不足可能意味著可能有更有效的方法。以下是一些需要考慮的因素可能影響了我的發現的準確性或執行時間:
最後,我想指出,這是我第一次使用 PyTorch 做任何事,它的性能給我留下了深刻的印象。
當我陷入困境時,我沒想到會看到效能上的如此提升。我了解了張量背後的想法以及一些有關計算更複雜的任務背後的支援機制的知識。您可以隨意使用、複製或修改程式碼片段。
感謝您對我的包容,希望您閱讀愉快。
下次再見,
乾杯。 ?
以上是一次彩票探索如何讓我了解 PyTorch 的強大功能的詳細內容。更多資訊請關注PHP中文網其他相關文章!