Как решить таймаут Google Colab и Drive

Если вы новичок в работе с миллионами файлов для анализа данных с помощью Google Colab и Google Drive, у меня есть несколько новостей: речь идет не только об алгоритмах, наборах для обучения / разработки / тестирования или настройке параметров. Управление системными файлами очень важно для успеха вашего проекта в области науки о данных.

Я кое-что узнал об этом на собственном горьком опыте, когда работал над диссертацией.

Моя диссертация

Моя диссертация посвящена генерации естественного языка на основе аудиофайлов, для этого у меня есть 1,6 миллиона файлов.

Кроме того, я хочу использовать графический процессор Google Colab для обучения моей модели и Google Drive для хранения моих данных.

Что я сделал первым

Я только что загрузил все свои данные в папку «Data» на моем Google Диске, используя следующую функцию:

def uploader(file, filename):
    file1 = drive.CreateFile({"parents": [{"kind": "drive#fileLink",   "id": ‘<my_folder_id>’ }],"title": filename})
    file1.SetContentFile(file)
    file1.Upload()

Затем этот «цикл for» загрузил каждый файл на Google Диск.

for i in range(0,len(my_files)):
    
    file=path+my_files[i]
    filename=my_files[i]
    uploader(file, filename)

Что я нашел

Возникает ошибка тайм-аута чтения, подобная следующей:

Это происходит, когда у вас есть тысячи файлов в вашем каталоге, и если вы не можете прочитать свои данные, вы не сможете обучить свою модель, и ваш проект завершится ошибкой.

Теоретическое решение

Мой научный руководитель порекомендовал мне создать подпапки, чтобы не повредить файловую систему и избежать проблемы с тайм-аутом в Google Colab, когда я пытаюсь их прочитать.

Как это работает?

Представьте, что у вас есть 3 файла с именами:

  • ааб
  • аба
  • баа

Идея состоит в том, чтобы создавать подпапки на основе первой буквы их имен, затем второй буквы и так далее.

Помните, что моя основная папка - это «Данные», у меня есть три файла, и в этом случае я создам два уровня вложенных папок.

Первый уровень вложенных папок:

Первый уровень основан на первой букве каждого файла, учитывая, что у меня есть файлы, в моем каталоге будет два подкаталога.

Данные /

├── a

├── b

Второй уровень вложенных папок:

Второй уровень основан на второй букве каждого файла, учитывая файлы, которые у меня есть, теперь каждая из моих подпапок будет иметь:

a/

├── a

├── b

b/

├── a

Таким образом, наши окончательные каталоги для чтения каждого из наших файлов:



Кодовое решение

Вспомогательные функции

«Листа» на самом деле помощник помощников. Это полезно для получения имен вложенных папок (и файлов) и их идентификаторов. Следуя примеру, если мы применим его к «… / Data», мы получим имена подпапок (a и b) и их идентификаторы.

def lista(file_list):
    title=[]
    idx=[]
    for file in file_list:
        title.append(file['title'])
        idx.append(file['id'])
        
    dictionary = dict(zip(title, idx))
    
    return title,dictionary

«Проверка» сообщает, сколько вложенных папок должна создать функция «Основная». Кроме того, он возвращает «helper_path», который является идентификатором уже созданного более глубокого подкаталога.

def verification(file_list,helper):
    helper_path=first_path
    
    file_list_helper=file_list
    start_range=0
    
    title,dictionary=lista(file_list_helper)
    
    letter=helper[0]
    
     
    if letter in title:
        
        helper_path = dictionary[letter]
        file_list_helper = drive.ListFile({'q': "'"+helper_path+"'"+" in parents and trashed=false"}).GetList()
        start_range+=1    
        
        for i in range(1,tree_depth):
                
                title,dictionary=lista(file_list_helper)
                letter=helper[i]
                
                if letter in title:
        
                    helper_path = dictionary[letter]
                    file_list_helper = drive.ListFile({'q':  "'"+helper_path+"'"+" in parents and trashed=false"}).GetList()
                    start_range+=1    
                    
                else:
                    break                          
            
    return start_range,helper_path

«Подкаталог» создает папки подкаталога и принимает три параметра: «Helper_path», «helper» и «i».

«Helper_path» - это идентификатор последней созданной подпапки, «i» - это i из «цикла for», а буква в позиции i станет именем подпапки, которая будет создана.

def subdirectory(path,helper,i):
    
    letter=helper[i]
              
    sd = drive.CreateFile({'title':letter, 
                                                       "parents":  [{"id": path}], 
                                                       "mimeType": "application/vnd.google-apps.folder"}) 
    sd.Upload()
    file_list = drive.ListFile({'q': "'"+path+"'"+" in parents and trashed=false"}).GetList()
    title,dictionary=lista(file_list)
    
    if letter in title:
        return_path = dictionary[letter]
            
                    
    return return_path

Load »загружает файл на Google Диск и имеет три параметра:« last_path »,« file »и« filename ». «Last_path» - это идентификатор целевой папки, и он нужен вам, чтобы поместить файл в нужное место. «Имя файла» - это имя, которое файл появится в папке назначения. «Файл» - это каталог вашего файла на жестком диске, куда идет код, чтобы взять файл для его загрузки. Кроме того, эта функция проверяет, существует ли уже файл в папке назначения, и избегает загрузки одного и того же файла дважды.

def load(last_path,helper_2):
    file_h = drive.CreateFile({"parents": [{"kind": "drive#fileLink", "id": last_path}],"title": helper_2})
    
    destiny=drive.ListFile({'q': "'"+last_path+"'"+" in parents and trashed=false"}).GetList()
    title,_=lista(destiny)
    
    if helper_2 not in title:
    
        
        file_h.SetContentFile(file)
        file_h.Upload()

Функция main использует всех этих помощников для достижения этой цели следующим образом:

  1. Удалите пробелы и строчные заглавные буквы, если они существуют. Если у вас есть файл с названием «День из жизни», цель состоит в том, чтобы получить «adayinthelife», чтобы избежать пробелов и иметь подпапки, такие как «A» или «a».
  2. Загрузите словарь, в котором мы храним идентификаторы назначения папок. Цель состоит в том, чтобы ускорить процесс, если папка назначения уже создана. Если целевая папка существует, код пропускает шаг 3 и выполняет шаг 4.
  3. Мы определяем, сколько новых вложенных папок нам следует создать. Например, если у нас есть новый файл с именем «aca», а у нас уже есть «… Data / a», нам нужно создать только «c».
  4. Загружаем наши данные.
  5. Мы добавляем новый идентификатор папки назначения в наш словарь (на случай, если мы только что создали его).
def main(file,filename,first_path,tree_depth):
    
    helper_2=filename
    
    
    helper=helper_2.strip()
    helper=helper.lower()
    helper=helper.replace(" ", "")     
     
     direc_dic=np.load('directorio_dict.npy',allow_pickle='TRUE').item()
    
    for i in range(tree_depth):
        if i==0:
            direc=helper[i]
        else:
            direc=direc+helper[i]
            
    if direc in direc_dic:
        helper_path=direc_dic[direc]
        load(helper_path,helper_2)
    
    else:
        file_list = drive.ListFile({'q': "'"+first_path+"'"+" in parents and trashed=false"}).GetList()
        start_range, helper_path=verification(file_list,helper)
        if start_range<tree_depth:
            for i in range(start_range,tree_depth):
                helper_path=subdirectory(helper_path,helper,i)
            load(helper_path,helper_2)
            
            direc_dic[direc]=helper_path
            np.save('directorio_dict.npy', direc_dic) 
        if start_range==tree_depth:
            load(helper_path,helper_2)
            direc_dic[direc]=helper_path
            np.save('directorio_dict.npy', direc_dic)

Последний шаг

Лично я предпочитаю запускать Организатор из другого блокнота Jupyter. Этот дополнительный блокнот под названием «Massive_uploader» полезен для входа в вашу учетную запись Google, настройки Организатора и создания «цикла for» для загрузки всех нужных файлов.

Сначала убедитесь, что вы включили API Google Диска, а затем выполните следующий блок кода. В вашем браузере откроется новая вкладка.

from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive
import os
g_login = GoogleAuth()
g_login.LocalWebserverAuth()
drive = GoogleDrive(g_login)

Затем пора определить, сколько подуровней вы хотите с помощью tree_depth и идентификатора папки, в которую вы будете загружать свои данные на свой Google Диск с помощью first_path.

import numpy as np
import re 
tree_depth=3
first_path='your_main_folder_id'

Вы можете получить id (first_path) из URL. Представьте, что вы уже находитесь в папке, в которой хотите создать подпапки и хранить все свои данные. Идентификатор (first_path) - это номер после последнего «/».

Чтобы получить данные, которые вы хотите загрузить, сначала вы определяете путь. Путь - это место, где вы храните свои данные локально. Например, в моем случае это «/ home / facudeza / tesis». Затем мы извлекаем все файлы, которые есть в пути.

path='directory_where_you_have_your_data_on_your_hard_disk'
my_files=os.listdir(path)

Затем убедитесь, что вы загрузили блокнот Organizer в свой каталог Jupyter и вызываете его.

%run ./Organizer.ipynb

Наконец, вы выполняете цикл загрузки файлов.

for i in range(0,len(my_files)):
    
    file=path+my_files[i]
    filename=my_files[i]
    main(file,filename,first_path,tree_depth)

Вы можете ускорить процесс, создавая копии Massive_uploader и выполняя их параллельно, но будьте осторожны, чтобы не превысить вашу квоту API.

Заключение

Таким образом я понял, как справиться с этой проблемой и облегчить чтение моих файлов из Google Colab.

Вы можете скачать Органайзер и Massive_uploader,

Если у вас есть совет, рекомендация или комментарий, мы будем рады их приветствовать.

Спасибо за чтение.

Вам понравился этот пост?
Порекомендуйте, поделившись им в социальных сетях

Хотите вместе со мной читать и изучать науку о данных?
Подписывайтесь на меня на Medium