欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Paddle模型性能分析工具Profiler定位瓶頸點優(yōu)化程序詳解

 更新時間:2023年03月10日 11:51:02   作者:汀丶  
這篇文章主要為大家介紹了Paddle模型性能分析工具Profiler定位瓶頸點優(yōu)化程序詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

Paddle模型性能分析Profiler

定位性能瓶頸點優(yōu)化程序提升性能

Paddle Profiler是飛槳框架自帶的低開銷性能分析器,可以對模型運行過程的性能數(shù)據(jù)進行收集、統(tǒng)計和展示。性能分析器提供的數(shù)據(jù)可以幫助定位模型的瓶頸,識別造成程序運行時間過長或者GPU利用率低的原因,從而尋求優(yōu)化方案來獲得性能的提升。

1.使用Profiler工具調(diào)試程序性能

在模型性能分析中,通常采用如下四個步驟:

  • 獲取模型正常運行時的ips(iterations per second, 每秒的迭代次數(shù)),給出baseline數(shù)據(jù)。
  • 開啟性能分析器,定位性能瓶頸點。
  • 優(yōu)化程序,檢查優(yōu)化效果。
  • 獲取優(yōu)化后模型正常運行時的ips,和baseline比較,計算真實的提升幅度。

下面是使用神經(jīng)網(wǎng)絡(luò)對cifar10進行分類的示例代碼,里面加上了啟動性能分析的代碼。通過這個比較簡單的示例,來看性能分析工具是如何通過上述四個步驟在調(diào)試程序性能中發(fā)揮作用。

1.1 使用cifar10數(shù)據(jù)集卷積神經(jīng)網(wǎng)絡(luò)進行圖像分類

import paddle
import paddle.nn.functional as F
from paddle.vision.transforms import ToTensor
import numpy as np
import matplotlib.pyplot as plt
print(paddle.__version__)

加載數(shù)據(jù)集

cifar10數(shù)據(jù)集由60000張大小為32 * 32的彩色 圖片組成,其中有50000張圖片組成了訓(xùn)練集,另外10000張圖片組成了測試集。這些圖片分為10個類別,將訓(xùn)練一個模型能夠把圖片進行正確的分類。

transform = ToTensor()
cifar10_train = paddle.vision.datasets.Cifar10(mode='train',
                                               transform=transform)
cifar10_test = paddle.vision.datasets.Cifar10(mode='test',
                                              transform=transform)

組建網(wǎng)絡(luò)

接下來使用飛槳定義一個使用了三個二維卷積( Conv2D ) 且每次卷積之后使用 relu 激活函數(shù),兩個二維池化層( MaxPool2D ),和兩個線性變換層組成的分類網(wǎng)絡(luò),來把一個(32, 32, 3)形狀的圖片通過卷積神經(jīng)網(wǎng)絡(luò)映射為10個輸出,這對應(yīng)著10個分類的類別

class MyNet(paddle.nn.Layer):
    def __init__(self, num_classes=1):
        super(MyNet, self).__init__()
        self.conv1 = paddle.nn.Conv2D(in_channels=3, out_channels=32, kernel_size=(3, 3))
        self.pool1 = paddle.nn.MaxPool2D(kernel_size=2, stride=2)
        self.conv2 = paddle.nn.Conv2D(in_channels=32, out_channels=64, kernel_size=(3,3))
        self.pool2 = paddle.nn.MaxPool2D(kernel_size=2, stride=2)
        self.conv3 = paddle.nn.Conv2D(in_channels=64, out_channels=64, kernel_size=(3,3))
        self.flatten = paddle.nn.Flatten()
        self.linear1 = paddle.nn.Linear(in_features=1024, out_features=64)
        self.linear2 = paddle.nn.Linear(in_features=64, out_features=num_classes)
    def forward(self, x):
        x = self.conv1(x)
        x = F.relu(x)
        x = self.pool1(x)
        x = self.conv2(x)
        x = F.relu(x)
        x = self.pool2(x)
        x = self.conv3(x)
        x = F.relu(x)
        x = self.flatten(x)
        x = self.linear1(x)
        x = F.relu(x)
        x = self.linear2(x)
        return x

模型訓(xùn)練&預(yù)測

接下來,用一個循環(huán)來進行模型的訓(xùn)練,將會:

使用 paddle.optimizer.Adam 優(yōu)化器來進行優(yōu)化。

使用 F.cross_entropy 來計算損失值。

使用 paddle.io.DataLoader 來加載數(shù)據(jù)并組建batch。

import paddle.profiler as profiler
#參數(shù)設(shè)置
epoch_num = 10
batch_size = 32
learning_rate = 0.001
val_acc_history = []
val_loss_history = []
def train(model):
    print('start training ... ')
    # turn into training mode
    model.train()
    opt = paddle.optimizer.Adam(learning_rate=learning_rate,
                                parameters=model.parameters())
    train_loader = paddle.io.DataLoader(cifar10_train,
                                        shuffle=True,
                                        batch_size=batch_size,
                                        num_workers=4)
    valid_loader = paddle.io.DataLoader(cifar10_test, batch_size=batch_size)
    # 創(chuàng)建性能分析器相關(guān)的代碼
    def my_on_trace_ready(prof):# 定義回調(diào)函數(shù),性能分析器結(jié)束采集數(shù)據(jù)時會被調(diào)用
        callback = profiler.export_chrome_tracing('./profiler_demo') # 創(chuàng)建導(dǎo)出性能數(shù)據(jù)到profiler_demo文件夾的回調(diào)函數(shù)
        callback(prof)  # 執(zhí)行該導(dǎo)出函數(shù)
        prof.summary(sorted_by=profiler.SortedKeys.GPUTotal) # 打印表單,按GPUTotal排序表單項
    p = profiler.Profiler(scheduler = [3,14], on_trace_ready=my_on_trace_ready, timer_only=True) # 初始化Profiler對象
    p.start() # 性能分析器進入第0個step
    for epoch in range(epoch_num):
        for batch_id, data in enumerate(train_loader()):
            x_data = data[0]
            y_data = paddle.to_tensor(data[1])
            y_data = paddle.unsqueeze(y_data, 1)
            logits = model(x_data)
            loss = F.cross_entropy(logits, y_data)
            if batch_id % 1000 == 0:
                print("epoch: {}, batch_id: {}, loss is: {}".format(epoch, batch_id, loss.numpy()))
            loss.backward()
            opt.step()
            opt.clear_grad()
            p.step() # 指示性能分析器進入下一個step
            if batch_id == 19:
                p.stop() # 關(guān)閉性能分析器
                exit() # 做性能分析時,可以將程序提前退出
        # evaluate model after one epoch
        model.eval()
        accuracies = []
        losses = []
        for batch_id, data in enumerate(valid_loader()):
            x_data = data[0]
            y_data = paddle.to_tensor(data[1])
            y_data = paddle.unsqueeze(y_data, 1)
            logits = model(x_data)
            loss = F.cross_entropy(logits, y_data)
            acc = paddle.metric.accuracy(logits, y_data)
            accuracies.append(acc.numpy())
            losses.append(loss.numpy())
        avg_acc, avg_loss = np.mean(accuracies), np.mean(losses)
        print("[validation] accuracy/loss: {}/{}".format(avg_acc, avg_loss))
        val_acc_history.append(avg_acc)
        val_loss_history.append(avg_loss)
        model.train()
model = MyNet(num_classes=10)
train(model)
**部分結(jié)果展示:**
epoch: 6, batch_id: 0, loss is: [0.91811454]
epoch: 6, batch_id: 1000, loss is: [0.89851004]
[validation] accuracy/loss: 0.7232428193092346/0.8434960246086121
epoch: 7, batch_id: 0, loss is: [0.60690844]
epoch: 7, batch_id: 1000, loss is: [0.6912922]
[validation] accuracy/loss: 0.7049720287322998/0.887704074382782
epoch: 8, batch_id: 0, loss is: [0.6330824]
epoch: 8, batch_id: 1000, loss is: [0.5715592]
[validation] accuracy/loss: 0.7176517844200134/0.8511289954185486
epoch: 9, batch_id: 0, loss is: [0.29487646]
epoch: 9, batch_id: 1000, loss is: [0.9094696]
[validation] accuracy/loss: 0.7097643613815308/0.9166476130485535

1.1.1 獲取性能調(diào)試前模型正常運行的ips

上述程序在創(chuàng)建Profiler時候,timer_only設(shè)置的值為True,此時將只開啟benchmark功能,不開啟性能分析器,程序輸出模型正常運行時的benchmark信息如下

  • Reader Ratio:表示數(shù)據(jù)讀取部分占訓(xùn)練batch迭代過程的時間占比,
  • reader_cost:代表數(shù)據(jù)讀取時間,
  • batch_cost:代表batch迭代的時間,
  • ips:表示每秒能迭代多少次,即跑多少個batch。

可以看到,此時的ips為70.99,可將這個值作為優(yōu)化對比的baseline。

 ============================================Perf Summary============================================
 Reader Ratio: 35.240%
 Time Unit: s, IPS Unit: steps/s
|                 |       avg       |       max       |       min       |
 |   reader_cost   |     0.00496     |     0.00542     |     0.00469     |
|    batch_cost   |     0.01408     |     0.01325     |     0.01246     |
 |       ips       |     70.99914    |     80.24470    |     75.46403    |

1.1.2. 開啟性能分析器,定位性能瓶頸點

修改程序,將Profiler的timer_only參數(shù)設(shè)置為False, 此時代表不只開啟benchmark功能,還將開啟性能分析器,進行詳細的性能分析。

p = profiler.Profiler(scheduler = [3,14], on_trace_ready=my_on_trace_ready, timer_only=False)

性能分析器會收集程序在第3到14次(不包括14)訓(xùn)練迭代過程中的性能數(shù)據(jù),并在profiler_demo文件夾中輸出一個json格式的文件,用于展示程序執(zhí)行過程的timeline,可通過chrome瀏覽器的chrome://tracing 插件打開這個文件進行查看。

如圖所示,把json文件load即可:

性能分析器還會直接在終端打印統(tǒng)計表單(建議重定向到文件中查看),查看程序輸出的Model Summary表單

-----------------------------------------------Model Summary-----------------------------------------------
Time unit: ms
---------------  ------  ----------------------------------------  ----------------------------------------  
Name             Calls   CPU Total / Avg / Max / Min / Ratio(%)    GPU Total / Avg / Max / Min / Ratio(%)    
---------------  ------  ----------------------------------------  ----------------------------------------  
ProfileStep      11      138.99 / 12.64 / 17.91 / 10.65 / 100.00   8.81 / 0.80 / 0.80 / 0.80 / 100.00        
  Dataloader     11      16.88 / 1.53 / 6.91 / 0.09 / 12.14        0.00 / 0.00 / 0.00 / 0.00 / 0.00          
  Forward        11      45.18 / 4.11 / 4.41 / 3.61 / 32.50        2.73 / 0.25 / 0.25 / 0.25 / 31.01         
  Backward       11      27.63 / 2.51 / 2.85 / 2.37 / 19.88        4.04 / 0.37 / 0.37 / 0.36 / 45.81         
  Optimization   11      19.75 / 1.80 / 1.89 / 1.61 / 14.21        1.05 / 0.10 / 0.10 / 0.09 / 11.56         
  Others         -       29.55 / - / - / - / 21.26                 1.05 / - / - / - / 11.63                  
---------------  ------  ----------------------------------------  ----------------------------------------  
Note:
在此表中,GPU 時間是該階段調(diào)用的所有設(shè)備(GPU)事件的總和。
與概述摘要不同,如果兩個設(shè)備(GPU)事件在不同的流上執(zhí)行重疊時間,我們直接在這里求和。
  • 其中ProfileStep表示訓(xùn)練batch的迭代step過程,對應(yīng)代碼中每兩次調(diào)用p.step()的間隔時間;
  • Dataloader表示數(shù)據(jù)讀取的時間,即for batch_id, data in enumerate(train_loader())的執(zhí)行時間;
  • Forward表示模型前向的時間,即logits = model(x_data)的執(zhí)行時間,
  • Backward表示反向傳播的時間,即loss.backward()的執(zhí)行時間;
  • Optimization表示優(yōu)化器的時間,即opt.step()的執(zhí)行時間。

通過timeline可以看到,Dataloader占了執(zhí)行過程的很大比重,Model Summary顯示其接近了12%。分析程序發(fā)現(xiàn),這是由于模型本身比較簡單,需要的計算量小,再加上Dataloader 準(zhǔn)備數(shù)據(jù)時只用了單進程來讀取,使得程序讀取數(shù)據(jù)時和執(zhí)行計算時沒有并行操作,導(dǎo)致Dataloader占比過大。

1.1.3. 優(yōu)化程序,檢查優(yōu)化效果

識別到了問題產(chǎn)生的原因,對程序繼續(xù)做如下修改,將Dataloader的num_workers設(shè)置為4,使得能有多個進程并行讀取數(shù)據(jù)。

train_loader = paddle.io.DataLoader(cifar10_train,
                                    shuffle=True,
                                    batch_size=batch_size,
                                    num_workers=4)

重新對程序進行性能分析,新的timeline和Model Summary如下所示

-----------------------------------------------Model Summary-----------------------------------------------
Time unit: ms
---------------  ------  ----------------------------------------  ----------------------------------------  
Name             Calls   CPU Total / Avg / Max / Min / Ratio(%)    GPU Total / Avg / Max / Min / Ratio(%)    
---------------  ------  ----------------------------------------  ----------------------------------------  
ProfileStep      11      89.44 / 8.13 / 8.76 / 7.82 / 100.00       8.82 / 0.80 / 0.80 / 0.80 / 100.00        
  Dataloader     11      1.51 / 0.14 / 0.16 / 0.12 / 1.69          0.00 / 0.00 / 0.00 / 0.00 / 0.00          
  Forward        11      31.67 / 2.88 / 3.17 / 2.82 / 35.41        2.72 / 0.25 / 0.25 / 0.24 / 36.11         
  Backward       11      25.35 / 2.30 / 2.49 / 2.20 / 28.34        4.07 / 0.37 / 0.37 / 0.37 / 42.52         
  Optimization   11      11.67 / 1.06 / 1.16 / 1.01 / 13.04        1.04 / 0.09 / 0.10 / 0.09 / 10.59         
  Others         -       19.25 / - / - / - / 21.52                 1.06 / - / - / - / 10.78                  
---------------  ------  ----------------------------------------  ----------------------------------------

可以看到,從Dataloader中取數(shù)據(jù)的時間大大減少,從12%變成了平均只占一個step的1.69%,并且平均一個step所需要的時間也相應(yīng)減少了從1.53到0.14。

### 1.1.4 獲取優(yōu)化后模型正常運行的ips,確定真實提升幅度
重新將timer_only設(shè)置的值為True,獲取優(yōu)化后模型正常運行時的benchmark信息
============================================Perf Summary============================================
Reader Ratio: 1.718%
Time Unit: s, IPS Unit: steps/s
|                 |       avg       |       max       |       min       |
|   reader_cost   |     0.00013     |     0.00015     |     0.00012     |
|    batch_cost   |     0.00728     |     0.00690     |     0.00633     |
|       ips       |    137.30879    |    158.01126    |    144.91796    |

此時從原來的Reader Ratio: 35.240%---->Reader Ratio: 1.718%

ips的值變成了137.3,相比優(yōu)化前的baseline70.99,模型真實性能提升了193%。

注意點:

由于Profiler開啟的時候,收集性能數(shù)據(jù)本身也會造成程序性能的開銷,因此正常跑程序時請不要開啟性能分析器,性能分析器只作為調(diào)試程序性能時使用。

  • 1.如果想獲得程序正常運行時候的 benchmark信息(如ips),可以像示例一樣將Profiler的timer_only參數(shù)設(shè)置為True,此時不會進行詳盡的性能數(shù)據(jù)收集,幾乎不影響程序正常運行的性能,所獲得的benchmark信息也趨于真實。
  • 2.benchmark信息計算的數(shù)據(jù)范圍是從調(diào)用Profiler的start方法開始,到調(diào)用stop方法結(jié)束這個過程的數(shù)據(jù)。而Timeline和性能數(shù)據(jù)的統(tǒng)計表單的數(shù)據(jù)范圍是所指定的采集區(qū)間,如這個例子中的第3到14次迭代,這會導(dǎo)致開啟性能分析器時統(tǒng)計表單和benchmark信息輸出的值不同(如統(tǒng)計到的Dataloader的時間占比)。
  • 3.當(dāng)benchmark統(tǒng)計的范圍和性能分析器統(tǒng)計的范圍不同時, 由于benchmark統(tǒng)計的是平均時間,如果benchmark統(tǒng)計的范圍覆蓋了性能分析器開啟的范圍,也覆蓋了關(guān)閉性能調(diào)試時的正常執(zhí)行的范圍,此時benchmark的值沒有意義,因此開啟性能分析器時請以性能分析器輸出的統(tǒng)計表單為參考,這也是為何上面示例里在開啟性能分析器時沒貼benchmark信息的原因。

1.1.5 結(jié)果展示

#結(jié)果展示
plt.plot(val_acc_history, label = 'validation accuracy')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.ylim([0.5, 0.8])
plt.legend(loc='lower right')

2 統(tǒng)計表單展示

統(tǒng)計表單負責(zé)對采集到的數(shù)據(jù)(Event)從多個不同的角度進行解讀,也可以理解為對timeline進行一些量化的指標(biāo)計算。 目前提供Device Summary、Overview Summary、Model Summary、Distributed Summary、Operator Summary、Kernel Summary、Memory Manipulation Summary和UserDefined Summary的統(tǒng)計表單,每個表單從不同的角度進行統(tǒng)計計算。每個表單的統(tǒng)計內(nèi)容簡要敘述如下:

Device Summary

-------------------Device Summary-------------------
------------------------------  --------------------  
Device                          Utilization (%)  
------------------------------  --------------------  
CPU(Process)                    77.13  
CPU(System)                     25.99  
GPU2                            55.50  
------------------------------  --------------------  
Note:
CPU(進程) 利用率 = 當(dāng)前進程在所有 cpu 內(nèi)核上的 CPU 時間/經(jīng)過的時間,因此最大利用率可以達到 100% * cpu 內(nèi)核數(shù)。
CPU(系統(tǒng))利用率=所有進程在所有cpu內(nèi)核上的CPU時間(忙碌時間)/(忙碌時間+空閑時間)。
GPU 利用率 = 當(dāng)前進程 GPU 時間 / 已用時間。
----------------------------------------------------

DeviceSummary提供CPU和GPU的平均利用率信息。其中

CPU(Process): 指的是進程的cpu平均利用率,算的是從Profiler開始記錄數(shù)據(jù)到結(jié)束這一段過程,進程所利用到的 cpu core的總時間與該段時間的占比。因此如果是多核的情況,對于進程來說cpu平均利用率是有可能超過100%的,因為同時用到的多個core的時間進行了累加。

CPU(System): 指的是整個系統(tǒng)的cpu平均利用率,算的是從Profiler開始記錄數(shù)據(jù)到結(jié)束這一段過程,整個系統(tǒng)所有進程利用到的cpu core總時間與該段時間乘以cpu core的數(shù)量的占比??梢援?dāng)成是從cpu的視角來算的利用率。

GPU: 指的是進程的gpu平均利用率,算的是從Profiler開始記錄數(shù)據(jù)到結(jié)束這一段過程,進程在gpu上所調(diào)用的kernel的執(zhí)行時間 與 該段時間 的占比。

Overview Summary

Overview Summary用于展示每種類型的Event一共分別消耗了多少時間,對于多線程或多stream下,如果同一類型的Event有重疊的時間段,采取取并集操作,不對重疊的時間進行重復(fù)計算。

---------------------------------------------Overview Summary---------------------------------------------
Time unit: ms
-------------------------  -------------------------  -------------------------  -------------------------  
Event Type                 Calls                      CPU Time                   Ratio (%)  
-------------------------  -------------------------  -------------------------  -------------------------  
ProfileStep                8                          4945.15                    100.00  
  CudaRuntime              28336                      2435.63                    49.25  
  UserDefined              486                        2280.54                    46.12  
  Dataloader               8                          1819.15                    36.79  
  Forward                  8                          1282.64                    25.94  
  Operator                 8056                       1244.41                    25.16  
  OperatorInner            21880                      374.18                     7.57  
  Backward                 8                          160.43                     3.24  
  Optimization             8                          102.34                     2.07  
-------------------------  -------------------------  -------------------------  -------------------------  
                          Calls                      GPU Time                   Ratio (%)  
-------------------------  -------------------------  -------------------------  -------------------------  
  Kernel                   13688                      2744.61                    55.50  
  Memcpy                   496                        29.82                      0.60  
  Memset                   104                        0.12                       0.00  
  Communication            784                        257.23                     5.20  
-------------------------  -------------------------  -------------------------  -------------------------  
Note:
在此表中,我們根據(jù)事件類型匯總了所有收集到的事件。
在主機上收集的事件時間顯示為 CPU 時間,如果在設(shè)備上則顯示為 GPU 時間。
不同類型的事件可能會重疊或包含,例如 Operator 包括 OperatorInner,因此比率之和不是 100%。
有重疊的同類型事件的時間不會計算兩次,合并后所有時間相加。
Example:
Thread 1:
  Operator: |___________|     |__________|
Thread 2:
  Operator:   |____________|     |___|
After merged:
  Result:   |______________|  |__________|
----------------------------------------------------------------------------------------------------------

不在繼續(xù)詳細說明,參考項目即可:

項目鏈接,fork一下即可使用
aistudio.baidu.com/aistudio/pr…

以上就是Paddle模型性能分析工具Profiler定位瓶頸點優(yōu)化程序詳解的詳細內(nèi)容,更多關(guān)于Paddle分析工具Profiler的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 調(diào)整Jupyter notebook的啟動目錄操作

    調(diào)整Jupyter notebook的啟動目錄操作

    這篇文章主要介紹了調(diào)整Jupyter notebook的啟動目錄操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-04-04
  • python函數(shù)默認參數(shù)使用避坑指南

    python函數(shù)默認參數(shù)使用避坑指南

    這篇文章主要為大家介紹了python函數(shù)默認參數(shù)使用的踩雷避坑詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-07-07
  • Python文件打開讀取寫入方法實用案例

    Python文件打開讀取寫入方法實用案例

    我們在工作中經(jīng)常需要用python對文本文件進行內(nèi)容的讀取和寫入,下面這篇文章主要給大家介紹了關(guān)于Python文件打開讀取寫入方法的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2023-05-05
  • 使用Python來批量檢測并刪除Word文檔中的宏

    使用Python來批量檢測并刪除Word文檔中的宏

    Word文檔作為最常用的電子文檔格式之一,經(jīng)常被用來作為內(nèi)容分享工具,在網(wǎng)絡(luò)中或設(shè)備之間進行傳輸,其安全性也需要受到關(guān)注,宏是可嵌入Word文檔中的一種VBA迷你程序,本文將介紹如何使用Python來批量檢測并刪除Word文檔中的宏,保護計算機的安全,需要的朋友可以參考下
    2024-07-07
  • python異常的傳遞知識點總結(jié)

    python異常的傳遞知識點總結(jié)

    在本篇文章里小編給大家整理的是一篇關(guān)于python異常的傳遞知識點總結(jié),有興趣的朋友們可以學(xué)習(xí)下。
    2021-06-06
  • 解決PIP安裝第三方庫報錯SSL: CERTIFICATE_VERIFY_FAILED問題

    解決PIP安裝第三方庫報錯SSL: CERTIFICATE_VERIFY_FAILED問題

    這篇文章主要介紹了解決PIP安裝第三方庫報錯SSL: CERTIFICATE_VERIFY_FAILED問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • OpenCV 圖像繪制的實現(xiàn)

    OpenCV 圖像繪制的實現(xiàn)

    本文主要介紹了OpenCV 圖像繪制的實現(xiàn),主要包括直線,圓,多邊形和自定義圖形等,具有一定的參考價值,感興趣的可以了解一下
    2021-07-07
  • python方差檢驗的含義及用法

    python方差檢驗的含義及用法

    在本篇內(nèi)容里小編給大家整理的是一篇關(guān)于python方差檢驗的含義及用法,有需要的朋友們可以跟著學(xué)習(xí)參考下。
    2021-07-07
  • Python 實現(xiàn)自動完成A4標(biāo)簽排版打印功能

    Python 實現(xiàn)自動完成A4標(biāo)簽排版打印功能

    這篇文章主要介紹了Python 實現(xiàn)自動完成A4標(biāo)簽排版打印功能,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-04-04
  • 解決Python 爬蟲URL中存在中文或特殊符號無法請求的問題

    解決Python 爬蟲URL中存在中文或特殊符號無法請求的問題

    今天小編就為大家分享一篇解決Python 爬蟲URL中存在中文或特殊符號無法請求的問題。這種問題,初學(xué)者應(yīng)該都會遇到,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-05-05

最新評論