99999久久久久久亚洲,欧美人与禽猛交狂配,高清日韩av在线影院,一个人在线高清免费观看,啦啦啦在线视频免费观看www

熱線電話:13121318867

登錄
首頁(yè)精彩閱讀加快Python算法的四個(gè)方法:PyTorch
加快Python算法的四個(gè)方法:PyTorch
2020-06-05
收藏

CDA數(shù)據(jù)分析師 出品

相信大家在做一些算法經(jīng)常會(huì)被龐大的數(shù)據(jù)量所造成的超多計(jì)算量需要的時(shí)間而折磨的痛苦不已,接下來(lái)我們圍繞四個(gè)方法來(lái)幫助大家加快一下Python的計(jì)算時(shí)間,減少大家在算法上的等待時(shí)間。下面為大家講述有關(guān)PyTorch的內(nèi)容。

1.介紹:

PyTorch模塊中,我將展示如何使用torch和檢查、初始化GPU設(shè)備pycuda,以及如何使算法更快。

PyTorch是建立在torch的機(jī)器學(xué)習(xí)庫(kù)。它得到了Facebook AI研究小組的支持。在最近開發(fā)之后,由于它的簡(jiǎn)單性,動(dòng)態(tài)圖形以及它本質(zhì)上是Python,它在被開發(fā)出來(lái)之后變得非常流行。它的速度仍然沒有落后,在很多情況下可以說(shuō)是表現(xiàn)的非常好的。

pycuda允許你從python訪問(wèn)Nvidia的CUDA并行計(jì)算API。

2.如何檢查cuda的可用性?

要檢查是否有cuda可用的設(shè)備Torch,可以簡(jiǎn)單地運(yùn)行一下下面的代碼:

import torch
torch.cuda.is_available()
# True

3.如何獲取有關(guān)你的cuda設(shè)備的更多信息?

要獲取設(shè)備的基本信息,可以使用torch.cuda。但是,要獲取有關(guān)設(shè)備的更多信息,可以使用pycuda,這是一個(gè)圍繞CUDA庫(kù)開發(fā)的python包裝器。你可以使用:

import torch
import pycuda.driver as cuda
cuda.init()
##獲取默認(rèn)設(shè)備的Id
torch.cuda.current_device()
# 0
cuda.Device(0).name() # '0'是你的GPU的id
# Tesla K80

或者你可以這么用:

torch.cuda.get_device_name(0)#獲取ID為'0'的名稱設(shè)備
#'Tesla K80'

我編寫了一個(gè)簡(jiǎn)單的類來(lái)獲取有關(guān)cuda兼容GPU的信息:

#一個(gè)簡(jiǎn)單的類來(lái)了解你的cuda設(shè)備
import pycuda.driver as cuda
import pycuda.autoinit #必須使用它的功能
cuda.init() # 需要使用它的功能

class aboutCudaDevices():
    def __init__(self):
        pass
    
    def num_devices(self):
        """返回連接的設(shè)備數(shù)量."""
        return cuda.Device.count()
    
    def devices(self):
        """獲取所有連接設(shè)備的信息."""
        num = cuda.Device.count()
        print("%d device(s) found:"%num)
        for i in range(num):
            print(cuda.Device(i).name(), "(Id: %d)"%i)
            
    def mem_info(self):
        """獲得所有設(shè)備的可用內(nèi)存和總內(nèi)存."""
        available, total = cuda.mem_get_info()
        print("Available: %.2f GB\nTotal:     %.2f GB"%(available/1e9, total/1e9))
        
    def attributes(self, device_id=0):
        """獲取設(shè)備Id的屬性 = device_id"""
        return cuda.Device(device_id).get_attributes()
    
    def __repr__(self):
        """類表示為連接到它們的設(shè)備的數(shù)量."""
        num = cuda.Device.count()
        string = ""
        string += ("%d device(s) found:\n"%num)
        for i in range(num):
            string += ( "    %d) %s (Id: %d)\n"%((i+1),cuda.Device(i).name(),i))
            string += ("          Memory: %.2f GB\n"%(cuda.Device(i).total_memory()/1e9))
        return string

# 你可以通過(guò)輸入它的名字來(lái)打印輸出(__repr__):
aboutCudaDevices()
# 1 設(shè)備(年代):
#    1) Tesla K80 (Id: 0)
#          Memory: 12.00 GB

要獲取當(dāng)前的內(nèi)存使用情況,你可以使用pyTorch的函數(shù):

import torch
#返回當(dāng)前的GPU內(nèi)存使用
# 一個(gè)給定設(shè)備的容量(以字節(jié)為單位)
torch.cuda.memory_allocated()
#函數(shù)管理的當(dāng)前的GPU內(nèi)存
#以字節(jié)為給定設(shè)備緩存的分配器
torch.cuda.memory_cached()

在運(yùn)行應(yīng)用程序后,可以使用一個(gè)簡(jiǎn)單的命令來(lái)清除緩存:

# 釋放緩存分配器當(dāng)前持有的所有為占用的緩存內(nèi)存
# 以便這些內(nèi)存可以在其他GPU應(yīng)用程序中可以使用
# 并且可以在NVIDIA-SMI中可以進(jìn)行查看
torch.cuda.empty_cache()

但是,使用這個(gè)命令不會(huì)通過(guò)張量釋放占用的GPU內(nèi)存,因此它無(wú)法增加可用于PyTorch的GPU內(nèi)存量。

這些內(nèi)存方法僅適用于GPU。所以這才是真正需要它的地方。

4.如何存儲(chǔ)張量并在GPU上運(yùn)行模型?

使用.cuda函數(shù)。

如果你想要在CPU上存儲(chǔ)一些內(nèi)容,可以簡(jiǎn)單地編寫代碼:

a = torch.DoubleTensor([1., 2.])

這個(gè)向量是存儲(chǔ)在CPU上的,你對(duì)它執(zhí)行的任何操作都是在CPU上執(zhí)行完成的。而要將其轉(zhuǎn)移到GPU上,你只需要執(zhí)行以下操作.cuda:

a = torch.FloatTensor([1., 2.]).cuda()

或者,

a = torch.cuda.FloatTensor([1., 2.])

這將為它選擇默認(rèn)設(shè)備,該默認(rèn)設(shè)備可通過(guò)以下命令查看:

torch.cuda.current_device()
#0

或者,你也可以執(zhí)行以下操作:

a.get_device()
#0

你也可以將一個(gè)模型發(fā)送到GPU設(shè)備。例如,考慮一個(gè)簡(jiǎn)單的模塊nn.Sequential:

sq = nn.Sequential(
         nn.Linear(20,20),
         nn.ReLU(),
         nn.Linear(
         20,4 ),nn.Softmax()
)

要將其發(fā)送到GPU設(shè)備,只需執(zhí)行以下操作:

model = sq.cuda()

你可以檢查它是否在GPU設(shè)備上,為此,你必須檢查它的參數(shù)是否在GPU設(shè)備上,例如:

#可以在這里進(jìn)行討論: discuss.pytorch.org/t/how-to-check-if-model-is-on-cuda
next(model.parameters()).is_cuda
# True

5.如果有多個(gè)GPU,如何選擇和使用GPU?

你可以為當(dāng)前應(yīng)用/存儲(chǔ)選擇一個(gè)GPU,該GPU可以與你上一個(gè)應(yīng)用/存儲(chǔ)選擇的GPU不同。

正如在第(2)部分中已經(jīng)看到的那樣,我們可以獲得所有與cuda兼容的設(shè)備及其Id使用pycuda的情況,在此我們就不再贅述了。

考慮到你有3個(gè)cuda兼容的設(shè)備,你可以初始化和分配tensors到一個(gè)特定的設(shè)備,就像這樣。

cuda0 = torch.device('cuda:0')
cuda1 = torch.device('cuda:1')
cuda2 = torch.device('cuda:2')
# 如果你只使用 'cuda' , 張量/型號(hào)將會(huì)被發(fā)送到默認(rèn)(當(dāng)前)設(shè)備。(默認(rèn)值= 0)
x = torch.Tensor([1., 2.], device=cuda1)
# 或者
x = torch.Tensor([1., 2.]).to(cuda1)
# 或者
x = torch.Tensor([1., 2.]).cuda(cuda1)
# 筆記:
# 如果你想改變默認(rèn)設(shè)備,那么請(qǐng)使用:
torch.cuda.set_device(2) # 設(shè)備Id為'2'的地方
# 如果你只想使用3個(gè)GPU中的2個(gè),那么你必須設(shè)置環(huán)境變量CUDA_VISIBLE_DEVICES 等于"0,2",如果你只想使用第一個(gè)和第三個(gè)GPU的話
#現(xiàn)在如果你想要檢查有多少個(gè)GPU時(shí),它將顯示兩個(gè)(0,1)
import os
os.environ["CUDA_VISIBLE_DEVICES"] = "0,2"

當(dāng)你對(duì)這些Tensors 進(jìn)行任何操作時(shí),無(wú)論選擇什么設(shè)備,都可以執(zhí)行該操作,結(jié)果會(huì)和Tensor保存在同一個(gè)設(shè)備上。

x = torch.Tensor([1., 2.]).to(cuda2)
y = torch.Tensor([3., 4.]).to(cuda2)
# 這個(gè)Tensor(張量)只會(huì)保存在'cuda2' 中
z = x + y

如果你有多個(gè)GPU,則可以在其中劃分應(yīng)用程序的工作,但是他們之間的通信會(huì)帶來(lái)開銷。但是,如果你不需要過(guò)多的進(jìn)行傳遞信息,那你可以嘗試一下。

實(shí)際上還有一個(gè)問(wèn)題。在PyTorch中的所有GPU操作中,默認(rèn)情況下都是異步的。盡管在CPU和GPU或兩個(gè)GPU之間復(fù)制數(shù)據(jù)時(shí)確實(shí)進(jìn)行了必要的同步,但是,如果你在命令torch.cuda.Stream()的幫助下創(chuàng)建自己的數(shù)據(jù)流,那么你講不得不處理指令的同步

舉一個(gè)PyTorch文檔中的例子,這是不正確的:

cuda = torch.device('cuda')
s = torch.cuda.Stream()  # 創(chuàng)建一個(gè)新的數(shù)據(jù)流.
A = torch.empty((100, 100), device=cuda).normal_(0.0, 1.0)
with torch.cuda.stream(s):
    # 因?yàn)?sum() 可能會(huì)在normal_()結(jié)束之前開始執(zhí)行!
    B = torch.sum(A)

如果你想充分利用多個(gè)GPU,那么你可以:

  1. 將所有GPU用于不同的任務(wù)/應(yīng)用程序
  2. 將每個(gè)GPU用于集合或堆棧中的一個(gè)模型,每個(gè)GPU都有數(shù)據(jù)副本(如果可能的話),因?yàn)榇蠖鄶?shù)處理是在擬合模型期間完成的,
  3. 在每個(gè)GPU中使用帶有切片輸入的每個(gè)GPU和模型副本。每個(gè)GPU都會(huì)分別計(jì)算結(jié)果,并將其結(jié)果發(fā)送到目標(biāo)GPU,然后再進(jìn)行進(jìn)一步的計(jì)算等。

6.數(shù)據(jù)并行性

在數(shù)據(jù)并行性中,我們將數(shù)據(jù)(從數(shù)據(jù)生成器中獲得的一個(gè)批次的數(shù)據(jù))分割為較小的小型批次的數(shù)據(jù),然后將其發(fā)送到多個(gè)GPU進(jìn)行并行計(jì)算。

PyTorch中,數(shù)據(jù)并行中是使用torch.nn.DataParallel實(shí)現(xiàn)的

我們將看到一個(gè)簡(jiǎn)單的例子來(lái)了解實(shí)際情況。為此,我們將必須使用nn.parallel的某些功能:

  1. Replicate(復(fù)制):Module在多個(gè)設(shè)備上復(fù)制。
  2. Scatter(分散):input將第一個(gè)維度分配到這些設(shè)備中。
  3. Gather(聚集):input收集并連接這些設(shè)備的第一個(gè)維度。
  4. parallel_apply:將我們從我們從Scatter中得到的一套分布式的input,輸入到相應(yīng)的分布式Module中,我們是通過(guò)復(fù)制得到的這些模塊。
#將模塊復(fù)制到設(shè)備id中的設(shè)備
replicas = nn.parallel.replicate(module, device_ids)
#將輸入分配到設(shè)備id中的設(shè)備
inputs = nn.parallel.scatter(input, device_ids)
#將模型應(yīng)用于相應(yīng)的輸入
outputs = nn.parallel.parallel_apply(replicas, inputs)
#收集所有設(shè)備的結(jié)果到output_device
result = nn.parallel.gather(outputs, output_device)

或者,只需要簡(jiǎn)單地:

model = nn.DataParallel(model, device_ids=device_ids)
result = model(input)

7.數(shù)據(jù)并行比較

訓(xùn)練集數(shù)據(jù)+Val w/數(shù)據(jù)加載器+SSD中對(duì)真實(shí)數(shù)據(jù)的數(shù)據(jù)擴(kuò)充

方式1*V100/CUDA 9/CuDNN 74*V100/CUDA 9/CuDNN 7Pytorch27分鐘10分鐘Keras(TF)38分鐘18分鐘Tensorflow33分鐘22分鐘Chainer29分鐘8分鐘MXNet(Gluon)29分鐘10分鐘

訓(xùn)練集W/在內(nèi)存中的綜合數(shù)據(jù)

方式1*V100/CUDA 9/CuDnn 74*V100/CUDA 9 / CuDNN 7Pytorch25分鐘8分鐘Keras(TF)36分鐘15分鐘Tensorflow25分鐘14分鐘Chainer27分鐘7分鐘MxNet(Gluon)28分鐘8分鐘

現(xiàn)在,你可以清楚的看到,即使必須在開始和結(jié)束時(shí)與主設(shè)備進(jìn)行通信,并行處理也絕對(duì)是有幫助的。并且僅在多GPU情況下,PyTorch比所有結(jié)果提供結(jié)果的時(shí)間更快僅僅略低于Chainer。Pytorch只需要通過(guò)對(duì)DataParallel的一次調(diào)用,就會(huì)使其變得簡(jiǎn)單。

8.torch.multiprocessing

torch.multiprocessing是Python multiprocessing模塊的包裝,其API與原始模塊100%兼容。因此,你可以在此處使用Python的多處理模塊中的Queue',Pipe',Array'等。此外,為了使其更快,他們添加了一個(gè)方法,share_memory_()該方法允許數(shù)據(jù)進(jìn)入一個(gè)狀態(tài),任何進(jìn)程都可以直接使用它,因此將該數(shù)據(jù)作為參數(shù)傳遞給不同的進(jìn)程將不會(huì)復(fù)制該數(shù)據(jù)。

你可以共享Tensors,模型的parameters,也可以根據(jù)需要在CPU或GPU上共享它們。

來(lái)自Pytorch的警告:(關(guān)于GPU上的共享)
   CUDA API要求導(dǎo)出到其他進(jìn)程的分配只要在被其他進(jìn)程使用時(shí)就保持有效。你應(yīng)該小心并確保你共享的CUDA Tensors在必要時(shí)不會(huì)超出范圍。這對(duì)于共享模型參數(shù)應(yīng)該不是問(wèn)題,但是傳遞其他類型的數(shù)據(jù)時(shí)應(yīng)格外小心。請(qǐng)注意,此限制不適用于共享CPU內(nèi)存。

你可以在此處的“池和進(jìn)程”部分中使用上面的方法,并且要獲得更快的速度,可以使用share_memory_()方法Tensor在所有進(jìn)程之間共享(例如)而不被復(fù)制。

# 
import torch.multiprocessing as mp
def train(model):
    for data, labels in data_loader:
        optimizer.zero_grad()
        loss_fn(model(data), labels).backward()
        optimizer.step()  # 這一步將更新共享參數(shù)
model = nn.Sequential(nn.Linear(n_in, n_h1),
                      nn.ReLU(),
                      nn.Linear(n_h1, n_out))
model.share_memory() # 需要 'fork' 方法工作
processes = []
for i in range(4): # No. 的過(guò)程
    p = mp.Process(target=train, args=(model,))
    p.start()
    processes.append(p)
for p in processes: p.join()

下一期我們繼續(xù)看加快Python計(jì)算的另一種方法——Numba~

數(shù)據(jù)分析咨詢請(qǐng)掃描二維碼

若不方便掃碼,搜微信號(hào):CDAshujufenxi

數(shù)據(jù)分析師資訊
更多

OK
客服在線
立即咨詢
客服在線
立即咨詢
') } function initGt() { var handler = function (captchaObj) { captchaObj.appendTo('#captcha'); captchaObj.onReady(function () { $("#wait").hide(); }).onSuccess(function(){ $('.getcheckcode').removeClass('dis'); $('.getcheckcode').trigger('click'); }); window.captchaObj = captchaObj; }; $('#captcha').show(); $.ajax({ url: "/login/gtstart?t=" + (new Date()).getTime(), // 加隨機(jī)數(shù)防止緩存 type: "get", dataType: "json", success: function (data) { $('#text').hide(); $('#wait').show(); // 調(diào)用 initGeetest 進(jìn)行初始化 // 參數(shù)1:配置參數(shù) // 參數(shù)2:回調(diào),回調(diào)的第一個(gè)參數(shù)驗(yàn)證碼對(duì)象,之后可以使用它調(diào)用相應(yīng)的接口 initGeetest({ // 以下 4 個(gè)配置參數(shù)為必須,不能缺少 gt: data.gt, challenge: data.challenge, offline: !data.success, // 表示用戶后臺(tái)檢測(cè)極驗(yàn)服務(wù)器是否宕機(jī) new_captcha: data.new_captcha, // 用于宕機(jī)時(shí)表示是新驗(yàn)證碼的宕機(jī) product: "float", // 產(chǎn)品形式,包括:float,popup width: "280px", https: true // 更多配置參數(shù)說(shuō)明請(qǐng)參見:http://docs.geetest.com/install/client/web-front/ }, handler); } }); } function codeCutdown() { if(_wait == 0){ //倒計(jì)時(shí)完成 $(".getcheckcode").removeClass('dis').html("重新獲取"); }else{ $(".getcheckcode").addClass('dis').html("重新獲取("+_wait+"s)"); _wait--; setTimeout(function () { codeCutdown(); },1000); } } function inputValidate(ele,telInput) { var oInput = ele; var inputVal = oInput.val(); var oType = ele.attr('data-type'); var oEtag = $('#etag').val(); var oErr = oInput.closest('.form_box').next('.err_txt'); var empTxt = '請(qǐng)輸入'+oInput.attr('placeholder')+'!'; var errTxt = '請(qǐng)輸入正確的'+oInput.attr('placeholder')+'!'; var pattern; if(inputVal==""){ if(!telInput){ errFun(oErr,empTxt); } return false; }else { switch (oType){ case 'login_mobile': pattern = /^1[3456789]\d{9}$/; if(inputVal.length==11) { $.ajax({ url: '/login/checkmobile', type: "post", dataType: "json", data: { mobile: inputVal, etag: oEtag, page_ur: window.location.href, page_referer: document.referrer }, success: function (data) { } }); } break; case 'login_yzm': pattern = /^\d{6}$/; break; } if(oType=='login_mobile'){ } if(!!validateFun(pattern,inputVal)){ errFun(oErr,'') if(telInput){ $('.getcheckcode').removeClass('dis'); } }else { if(!telInput) { errFun(oErr, errTxt); }else { $('.getcheckcode').addClass('dis'); } return false; } } return true; } function errFun(obj,msg) { obj.html(msg); if(msg==''){ $('.login_submit').removeClass('dis'); }else { $('.login_submit').addClass('dis'); } } function validateFun(pat,val) { return pat.test(val); }