PyTorch 遷移學(xué)習(xí)實(shí)戰(zhàn)
1. 實(shí)驗(yàn)環(huán)境
- Jupyter Notebook
- Python 3.7
- PyTorch 1.4.0
2. 實(shí)驗(yàn)?zāi)康?/h2>
遷移學(xué)習(xí),讓機(jī)器擁有能夠“舉一反三”的能力。
本次實(shí)驗(yàn)就以“是螞蟻還是蜜蜂”為例,探索如何將已訓(xùn)練好的大網(wǎng)絡(luò)遷移到小數(shù)據(jù)集上,并經(jīng)過少量數(shù)據(jù)集的訓(xùn)練就讓它獲得非常出眾的效果。
3. 相關(guān)原理
使用 PyTorch 的數(shù)據(jù)集套件從本地加載數(shù)據(jù)的方法
遷移訓(xùn)練好的大型神經(jīng)網(wǎng)絡(luò)模型到自己模型中的方法
遷移學(xué)習(xí)與普通深度學(xué)習(xí)方法的效果區(qū)別
兩種遷移學(xué)習(xí)方法的區(qū)別
4. 實(shí)驗(yàn)步驟
# 下載實(shí)驗(yàn)所需數(shù)據(jù)并解壓 !wget http://labfile.oss.aliyuncs.com/courses/1073/transfer-data.zip !unzip transfer-data.zip
4.1 數(shù)據(jù)收集
實(shí)驗(yàn)中的數(shù)據(jù)是已經(jīng)準(zhǔn)備好的,訓(xùn)練數(shù)據(jù)集在 ./data/train 中,校驗(yàn)數(shù)據(jù)集在 ./data/val 中。(推薦直接到藍(lán)橋云課上進(jìn)行實(shí)驗(yàn))。如果使用自己的環(huán)境只需要自己準(zhǔn)備相關(guān)圖片數(shù)據(jù),并將代碼中的路徑改成你自己的數(shù)據(jù)集路徑。
#引入實(shí)驗(yàn)所需要的包 import torch import torch.nn as nn import torch.optim as optim from torch.autograd import Variable import torch.nn.functional as F import numpy as np import torchvision from torchvision import datasets, models, transforms import matplotlib.pyplot as plt import time import copy import os
4.1.1加載數(shù)據(jù)
使用 datasets 的 ImageFolder 方法就可以實(shí)現(xiàn)自動(dòng)加載數(shù)據(jù),因?yàn)閿?shù)據(jù)集中的數(shù)據(jù)可能分別在不同的文件夾中,要讓所有的數(shù)據(jù)一起加載。
# 數(shù)據(jù)存儲(chǔ)總路徑 data_dir = 'transfer-data' # 圖像的大小為224*224 image_size = 224 # 從data_dir/train加載文件 # 加載的過程將會(huì)對(duì)圖像自動(dòng)作如下的圖像增強(qiáng)操作: # 1. 隨機(jī)從原始圖像中切下來一塊224*224大小的區(qū)域 # 2. 隨機(jī)水平翻轉(zhuǎn)圖像 # 3. 將圖像的色彩數(shù)值標(biāo)準(zhǔn)化 train_dataset = datasets.ImageFolder(os.path.join(data_dir, 'train'), transforms.Compose([ transforms.RandomResizedCrop(image_size), transforms.RandomHorizontalFlip(), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) ]) ) # 加載校驗(yàn)數(shù)據(jù)集,對(duì)每個(gè)加載的數(shù)據(jù)進(jìn)行如下處理: # 1. 放大到256*256像素 # 2. 從中心區(qū)域切割下224*224大小的圖像區(qū)域 # 3. 將圖像的色彩數(shù)值標(biāo)準(zhǔn)化 val_dataset = datasets.ImageFolder(os.path.join(data_dir, 'val'), transforms.Compose([ transforms.Resize(256), transforms.CenterCrop(image_size), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) ]) )
下面要為每個(gè)數(shù)據(jù)集創(chuàng)建數(shù)據(jù)加載器。
# 創(chuàng)建相應(yīng)的數(shù)據(jù)加載器 train_loader = torch.utils.data.DataLoader(train_dataset, batch_size = 4, shuffle = True, num_workers=4) val_loader = torch.utils.data.DataLoader(val_dataset, batch_size = 4, shuffle = True, num_workers=4) # 讀取得出數(shù)據(jù)中的分類類別數(shù) # 如果只有蜜蜂和螞蟻,那么是2 num_classes = len(train_dataset.classes) num_classes
輸出:2
4.1.2 GPU運(yùn)算
第一次了解GPU運(yùn)算是在第一篇博客PyTorch,簡(jiǎn)單的了解了一下。
深度學(xué)習(xí)可以通過 GPU 并行運(yùn)算加速模型的訓(xùn)練。
PyTorch 是支持使用 GPU 并行運(yùn)算的。但是能不能使用 GPU 加速運(yùn)算還取決于硬件,支持 GPU 的硬件(顯卡)一般是比較昂貴的。
如果你想讓自己的程序能夠自動(dòng)識(shí)別 GPU 計(jì)算環(huán)境,并且在 GPU 不具備的情況下也能自動(dòng)使用 CPU 正常運(yùn)行,可以這么做:
這三個(gè)變量,之后會(huì)用來靈活判斷是否需要采用 GPU 運(yùn)算。
# 檢測(cè)本機(jī)器是否安裝GPU,將檢測(cè)結(jié)果記錄在布爾變量use_cuda中 use_cuda = torch.cuda.is_available() # 當(dāng)可用GPU的時(shí)候,將新建立的張量自動(dòng)加載到GPU中 dtype = torch.cuda.FloatTensor if use_cuda else torch.FloatTensor itype = torch.cuda.LongTensor if use_cuda else torch.LongTensor
4.2 數(shù)據(jù)預(yù)處理
該函數(shù)作用:將數(shù)據(jù)集中的某張圖片打印出來。
def imshow(inp, title=None): # 將一張圖打印顯示出來,inp為一個(gè)張量,title為顯示在圖像上的文字 # 一般的張量格式為:channels * image_width * image_height # 而一般的圖像為 image_width * image_height * channels # 所以,需要將張量中的 channels 轉(zhuǎn)換到最后一個(gè)維度 inp = inp.numpy().transpose((1, 2, 0)) #由于在讀入圖像的時(shí)候所有圖像的色彩都標(biāo)準(zhǔn)化了,因此我們需要先調(diào)回去 mean = np.array([0.485, 0.456, 0.406]) std = np.array([0.229, 0.224, 0.225]) inp = std * inp + mean inp = np.clip(inp, 0, 1) #將圖像繪制出來 plt.imshow(inp) if title is not None: plt.title(title) plt.pause(0.001) # 暫停一會(huì)是為了能夠?qū)D像顯示出來。
將訓(xùn)練數(shù)據(jù)集的第一個(gè) batch 繪制出來:
#獲取第一個(gè)圖像batch和標(biāo)簽 images, labels = next(iter(train_loader)) # 將這個(gè)batch中的圖像制成表格繪制出來 out = torchvision.utils.make_grid(images) imshow(out, title=[train_dataset.classes[x] for x in labels])
4.3 創(chuàng)建模型
該實(shí)驗(yàn)先訓(xùn)練一個(gè)普通的卷積神經(jīng)網(wǎng)絡(luò),但正確率勉強(qiáng)達(dá)到50%上下。模型預(yù)測(cè)的效果很差。因?yàn)樵搶?shí)驗(yàn)選用的是螞蟻和蜜蜂的圖像數(shù)據(jù),本身就很難識(shí)別,簡(jiǎn)單的卷積神經(jīng)網(wǎng)絡(luò)應(yīng)付不了這種復(fù)雜的情況。其次,該實(shí)驗(yàn)的圖片訓(xùn)練樣本只有244個(gè),數(shù)量級(jí)太小。
代碼略
簡(jiǎn)單卷積神經(jīng)網(wǎng)絡(luò)取得的效果:(黃色曲線是測(cè)試數(shù)據(jù)集錯(cuò)誤率,藍(lán)色曲線是訓(xùn)練數(shù)據(jù)集錯(cuò)誤率。)
因此,這里提到使用“加載已訓(xùn)練好的 ResNet 進(jìn)行遷移學(xué)習(xí)”。
ResNet 是微軟亞洲研究院何凱明團(tuán)隊(duì)開發(fā)的一種極深的特殊的卷積神經(jīng)網(wǎng)絡(luò)。該網(wǎng)絡(luò)的原始版本曾號(hào)稱是“史上最深的網(wǎng)絡(luò)”,有 152 層,在物體分類等任務(wù)上具有較高的準(zhǔn)確度。
考慮到原始的 ResNet 具有較大的復(fù)雜性,在本次實(shí)驗(yàn)中,實(shí)際遷移的是一個(gè)具有 18 層的精簡(jiǎn)版的 ResNet。該網(wǎng)絡(luò)由 18 個(gè)串聯(lián)在一起的卷積模塊構(gòu)成,其中每一個(gè)卷積模塊都包括一層卷積一層池化。下面將加載 ResNet 模型,并觀察模型的組成部分。如果是第一次運(yùn)行,那么模型會(huì)被下載到 ~/.torch/models/ 文件夾中。
torch.utils.model_zoo.load_url('http://labfile.oss.aliyuncs.com/courses/1073/resnet18-5c106cde.pth') # 加載模型庫中的residual network,并設(shè)置pretrained為true,這樣便可加載相應(yīng)的權(quán)重 net = models.resnet18(pretrained=True) #如果存在GPU,就將網(wǎng)絡(luò)加載到GPU上 net = net.cuda() if use_cuda else net # 將網(wǎng)絡(luò)的架構(gòu)打印出來 net
從模型的組成部分中,可以看到最后有一層全連接層,也就是 (fc): Linear(in_features=512, out_features=1000)。
4.3.1 構(gòu)建遷移模型
下面把 ResNet18 中的卷積模塊作為特征提取層遷移過來,用于提取局部特征。同時(shí),將 ResNet18 中最后的全連接層(fc)替換,構(gòu)建一個(gè)包含 512 個(gè)隱含節(jié)點(diǎn)的全連接層,后接兩個(gè)結(jié)點(diǎn)的輸出層,用于最后的分類輸出。
整個(gè)模型的前面大部分的結(jié)構(gòu)都是 ResNet,最后兩層被替換成了自定義的全連接層。
# 讀取最后線性層的輸入單元數(shù),這是前面各層卷積提取到的特征數(shù)量 num_ftrs = net.fc.in_features # 重新定義一個(gè)全新的線性層,它的輸出為2,原本是1000 net.fc = nn.Linear(num_ftrs, 2) #如果存在GPU則將網(wǎng)絡(luò)加載到GPU中 net.fc = net.fc.cuda() if use_cuda else net.fc criterion = nn.CrossEntropyLoss() #Loss函數(shù)的定義 # 將網(wǎng)絡(luò)的所有參數(shù)放入優(yōu)化器中 optimizer = optim.SGD(net.parameters(), lr = 0.0001, momentum=0.9)
4.3.2 訓(xùn)練模型+測(cè)試+繪制圖表
在訓(xùn)練階段,遷移過來的 ResNet 模塊的結(jié)構(gòu)和所有超參數(shù)都可以保持不變,但是權(quán)重參數(shù)則有可能被新的數(shù)據(jù)重新訓(xùn)練。是否要更新這些舊模塊的權(quán)重參數(shù)完全取決于我們采取的遷移學(xué)習(xí)方式。
遷移學(xué)習(xí)主要有兩種模式:預(yù)訓(xùn)練模式和固定值模式。
接下來會(huì)分別介紹
4.3.2.1 預(yù)訓(xùn)練模式
record = [] #記錄準(zhǔn)確率等數(shù)值的容器 #開始訓(xùn)練循環(huán) num_epochs = 20 net.train(True) # 給網(wǎng)絡(luò)模型做標(biāo)記,標(biāo)志說模型在訓(xùn)練集上訓(xùn)練 best_model = net best_r = 0.0 for epoch in range(num_epochs): #optimizer = exp_lr_scheduler(optimizer, epoch) train_rights = [] #記錄訓(xùn)練數(shù)據(jù)集準(zhǔn)確率的容器 train_losses = [] for batch_idx, (data, target) in enumerate(train_loader): #針對(duì)容器中的每一個(gè)批進(jìn)行循環(huán) data, target = Variable(data), Variable(target) #將Tensor轉(zhuǎn)化為Variable,data為圖像,target為標(biāo)簽 #如果存在GPU則將變量加載到GPU中 if use_cuda: data, target = data.cuda(), target.cuda() output = net(data) #完成一次預(yù)測(cè) loss = criterion(output, target) #計(jì)算誤差 optimizer.zero_grad() #清空梯度 loss.backward() #反向傳播 optimizer.step() #一步隨機(jī)梯度下降 right = rightness(output, target) #計(jì)算準(zhǔn)確率所需數(shù)值,返回正確的數(shù)值為(正確樣例數(shù),總樣本數(shù)) train_rights.append(right) #將計(jì)算結(jié)果裝到列表容器中 loss = loss.cpu() if use_cuda else loss train_losses.append(loss.data.numpy()) #if batch_idx % 20 == 0: #每間隔100個(gè)batch執(zhí)行一次 #train_r為一個(gè)二元組,分別記錄訓(xùn)練集中分類正確的數(shù)量和該集合中總的樣本數(shù) train_r = (sum([tup[0] for tup in train_rights]), sum([tup[1] for tup in train_rights])) #在測(cè)試集上分批運(yùn)行,并計(jì)算總的正確率 net.eval() #標(biāo)志模型當(dāng)前為運(yùn)行階段 test_loss = 0 correct = 0 vals = [] #對(duì)測(cè)試數(shù)據(jù)集進(jìn)行循環(huán) for data, target in val_loader: #如果存在GPU則將變量加載到GPU中 if use_cuda: data, target = data.cuda(), target.cuda() data, target = Variable(data, requires_grad=True), Variable(target) output = net(data) #將特征數(shù)據(jù)喂入網(wǎng)絡(luò),得到分類的輸出 val = rightness(output, target) #獲得正確樣本數(shù)以及總樣本數(shù) vals.append(val) #記錄結(jié)果 #計(jì)算準(zhǔn)確率 val_r = (sum([tup[0] for tup in vals]), sum([tup[1] for tup in vals])) val_ratio = 1.0*val_r[0].numpy()/val_r[1] if val_ratio > best_r: best_r = val_ratio best_model = copy.deepcopy(net) #打印準(zhǔn)確率等數(shù)值,其中正確率為本訓(xùn)練周期Epoch開始后到目前撮的正確率的平均值 print('訓(xùn)練周期: {} \tLoss: {:.6f}\t訓(xùn)練正確率: {:.2f}%, 校驗(yàn)正確率: {:.2f}%'.format( epoch, np.mean(train_losses), 100. * train_r[0].numpy() / train_r[1], 100. * val_r[0].numpy()/val_r[1])) record.append([np.mean(train_losses), 1. * train_r[0].data.numpy() / train_r[1], 1. * val_r[0].data.numpy() / val_r[1]]) #繪制訓(xùn)練誤差曲線 x = [x[0] for x in record] y = [1 - x[1] for x in record] z = [1 - x[2] for x in record] #plt.plot(x) plt.figure(figsize = (10, 7)) plt.plot(y) plt.plot(z) plt.xlabel('Epoch') plt.ylabel('Error Rate')
測(cè)試模型,繪制分類效果
def visualize_model(model, num_images=6): images_so_far = 0 fig = plt.figure(figsize=(15,10)) for i, data in enumerate(val_loader): inputs, labels = data inputs, labels = Variable(inputs), Variable(labels) if use_cuda: inputs, labels = inputs.cuda(), labels.cuda() outputs = model(inputs) _, preds = torch.max(outputs.data, 1) preds = preds.cpu().numpy() if use_cuda else preds.numpy() for j in range(inputs.size()[0]): images_so_far += 1 ax = plt.subplot( 2,num_images//2, images_so_far) ax.axis('off') ax.set_title('predicted: {}'.format(val_dataset.classes[preds[j]])) imshow(data[0][j]) if images_so_far == num_images: return visualize_model(net) plt.ioff() plt.show()
4.3.2.2 固定值模式
遷移過來的部分網(wǎng)絡(luò)在結(jié)構(gòu)和權(quán)重上都保持固定的數(shù)值不會(huì)改變。
要想讓模型在固定值模式下訓(xùn)練,需要先鎖定網(wǎng)絡(luò)模型相關(guān)位置的參數(shù)。鎖定的方法非常簡(jiǎn)單,只要把網(wǎng)絡(luò)的梯度反傳標(biāo)志 requires_grad 設(shè)置為 False 就可以了。
# 加載residual網(wǎng)絡(luò)模型 net = torchvision.models.resnet18(pretrained=True) # 將模型放入GPU中 net = net.cuda() if use_cuda else net # 循環(huán)網(wǎng)絡(luò),將所有參數(shù)設(shè)為不更新梯度信息 for param in net.parameters(): param.requires_grad = False # 將網(wǎng)絡(luò)最后一層線性層換掉 num_ftrs = net.fc.in_features net.fc = nn.Linear(num_ftrs, 2) net.fc = net.fc.cuda() if use_cuda else net.fc criterion = nn.CrossEntropyLoss() #Loss函數(shù)的定義 # 僅將線性層的參數(shù)放入優(yōu)化器中 optimizer = optim.SGD(net.fc.parameters(), lr = 0.001, momentum=0.9) #訓(xùn)練模型 record = [] #記錄準(zhǔn)確率等數(shù)值的容器 #開始訓(xùn)練循環(huán) num_epochs = 4 net.train(True) # 給網(wǎng)絡(luò)模型做標(biāo)記,標(biāo)志說模型在訓(xùn)練集上訓(xùn)練 best_model = net best_r = 0.0 for epoch in range(num_epochs): #optimizer = exp_lr_scheduler(optimizer, epoch) train_rights = [] #記錄訓(xùn)練數(shù)據(jù)集準(zhǔn)確率的容器 train_losses = [] for batch_idx, (data, target) in enumerate(train_loader): #針對(duì)容器中的每一個(gè)批進(jìn)行循環(huán) data, target = Variable(data), Variable(target) #將Tensor轉(zhuǎn)化為Variable,data為圖像,target為標(biāo)簽 if use_cuda: data, target = data.cuda(), target.cuda() output = net(data) #完成一次預(yù)測(cè) loss = criterion(output, target) #計(jì)算誤差 optimizer.zero_grad() #清空梯度 loss.backward() #反向傳播 optimizer.step() #一步隨機(jī)梯度下降 right = rightness(output, target) #計(jì)算準(zhǔn)確率所需數(shù)值,返回正確的數(shù)值為(正確樣例數(shù),總樣本數(shù)) train_rights.append(right) #將計(jì)算結(jié)果裝到列表容器中 loss = loss.cpu() if use_cuda else loss train_losses.append(loss.data.numpy()) #train_r為一個(gè)二元組,分別記錄訓(xùn)練集中分類正確的數(shù)量和該集合中總的樣本數(shù) train_r = (sum([tup[0] for tup in train_rights]), sum([tup[1] for tup in train_rights])) #在測(cè)試集上分批運(yùn)行,并計(jì)算總的正確率 net.eval() #標(biāo)志模型當(dāng)前為運(yùn)行階段 test_loss = 0 correct = 0 vals = [] #對(duì)測(cè)試數(shù)據(jù)集進(jìn)行循環(huán) for data, target in val_loader: data, target = Variable(data, requires_grad=True), Variable(target) if use_cuda: data, target = data.cuda(), target.cuda() output = net(data) #將特征數(shù)據(jù)喂入網(wǎng)絡(luò),得到分類的輸出 val = rightness(output, target) #獲得正確樣本數(shù)以及總樣本數(shù) vals.append(val) #記錄結(jié)果 #計(jì)算準(zhǔn)確率 val_r = (sum([tup[0] for tup in vals]), sum([tup[1] for tup in vals])) val_ratio = 1.0*val_r[0].numpy()/val_r[1] if val_ratio > best_r: best_r = val_ratio best_model = copy.deepcopy(net) #打印準(zhǔn)確率等數(shù)值,其中正確率為本訓(xùn)練周期Epoch開始后到目前撮的正確率的平均值 print('訓(xùn)練周期: {} \tLoss: {:.6f}\t訓(xùn)練正確率: {:.2f}%, 校驗(yàn)正確率: {:.2f}%'.format( epoch, np.mean(train_losses), 100. * train_r[0].numpy() / train_r[1], 100. * val_r[0].numpy()/val_r[1])) record.append([np.mean(train_losses), 1. * train_r[0].data.numpy() / train_r[1], 1. * val_r[0].data.numpy() / val_r[1]]) # 繪制誤差曲線 x = [x[0] for x in record] y = [1 - x[1] for x in record] z = [1 - x[2] for x in record] #plt.plot(x) plt.figure(figsize = (10, 7)) plt.plot(y) plt.plot(z) plt.xlabel('Epoch') plt.ylabel('Error Rate') #展示分類結(jié)果 visualize_model(best_model) plt.ioff() plt.show()
4.4 結(jié)論
該實(shí)驗(yàn)中,預(yù)訓(xùn)練遷移模型取得的效果整體的錯(cuò)誤率比簡(jiǎn)單卷積神經(jīng)網(wǎng)絡(luò)低了很多。訓(xùn)練錯(cuò)誤率可以穩(wěn)定在 0.02 之下,測(cè)試錯(cuò)誤率大約在 0.07 左右。因?yàn)樵陬A(yù)訓(xùn)練模式下,模型對(duì)訓(xùn)練數(shù)據(jù)的擬合性比較強(qiáng),所以訓(xùn)練錯(cuò)誤率與測(cè)試錯(cuò)誤率差別較大。
在固定值遷移模式下,訓(xùn)練錯(cuò)誤率可以在 0.02 ~ 0.04 之間,比預(yù)訓(xùn)練模式稍高。測(cè)試錯(cuò)誤率大約在 0.07 左右,與預(yù)訓(xùn)練模式差不多。
因?yàn)楣潭ㄖ的J芥i定了大部分權(quán)重,模型對(duì)訓(xùn)練數(shù)據(jù)的擬合性沒那么強(qiáng),所以訓(xùn)練錯(cuò)誤率與測(cè)試錯(cuò)誤率的差別也沒那么大。
到此這篇關(guān)于PyTorch 遷移學(xué)習(xí)實(shí)戰(zhàn)的文章就介紹到這了,更多相關(guān)PyTorch 遷移內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用scrapy實(shí)現(xiàn)爬網(wǎng)站例子和實(shí)現(xiàn)網(wǎng)絡(luò)爬蟲(蜘蛛)的步驟
本文分二個(gè)示例,第一個(gè)是個(gè)簡(jiǎn)單的爬網(wǎng)站的小例子,第二個(gè)例子實(shí)現(xiàn)目是從一個(gè)網(wǎng)站的列表頁抓取文章列表,然后存入數(shù)據(jù)庫中,數(shù)據(jù)庫包括文章標(biāo)題、鏈接、時(shí)間,大家參考使用吧2014-01-01Python編程實(shí)現(xiàn)二分法和牛頓迭代法求平方根代碼
這篇文章主要介紹了Python編程實(shí)現(xiàn)二分法和牛頓迭代法求平方根代碼,具有一定參考價(jià)值,需要的朋友可以了解下。2017-12-12jupyter 使用Pillow包顯示圖像時(shí)inline顯示方式
這篇文章主要介紹了jupyter 使用Pillow包顯示圖像時(shí)inline顯示方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-04-04python requests 庫請(qǐng)求帶有文件參數(shù)的接口實(shí)例
今天小編就為大家分享一篇python requests 庫請(qǐng)求帶有文件參數(shù)的接口實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-01-01Python+PyQt5實(shí)現(xiàn)開發(fā)Memcached客戶端
這篇文章主要介紹了如何使用Python和PyQt5來制作一個(gè)Memcached客戶端,以便我們可以輕松地與Memcached服務(wù)器進(jìn)行交互,感興趣的小伙伴可以了解一下2023-06-06pytorch報(bào)錯(cuò)問題:ValueError: num_samples should be
這篇文章主要介紹了pytorch報(bào)錯(cuò)問題:ValueError: num_samples should be a positive integer value, but got num_samples=0的解決方案,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-02-02解決import tensorflow導(dǎo)致jupyter內(nèi)核死亡的問題
這篇文章主要介紹了解決import tensorflow導(dǎo)致jupyter內(nèi)核死亡的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-02-02