9 июня 2021 г. 9 вопросов на собеседовании по алгоритму CVTE NLP.

искусственный интеллект интервью алгоритм

1. Расскажите об улучшенном tf-idf

IDF в TF-IDF — это взвешивание, которое пытается подавить шум.Он просто считает, что слова с низкой частотностью текста более важны, а слова с более высокой частотой текста более бесполезны.Этот метод будет иметь огромные недостатки в подобных корпусах.Некоторые ключевые слова одного и того же текста легко маскируются. Например, если в корпусе D много образовательных статей, а текст j является в нем учебной статьей, то значение IDF слов, связанных с обучением, будет меньше, так что скорость припоминания извлечения ключевых слов в этой статье будет ниже.

Улучшенный метод: TF-IWF (Термин Частота-обратная частота слова)

В сезон зарядки ИИ откройте сундук с сокровищами и изучите обычный ценовой класс бесплатно!

Также есть 200 бумажных книг и т.д., приходите и присылайте! >>>В сезон зарядки ИИ откройте сундук с сокровищами и изучите полный ценовой класс бесплатно, и 200 бумажных книг будут доставлены бесплатно! -Онлайн июль

2. Поговорите о k-средних и спектральной кластеризации

Алгоритм кластеризации относится к алгоритму машинного обучения без учителя, то есть в нем нет метки категории y, а похожие данные необходимо группировать в группу по характеристикам данных. Алгоритм кластеризации K-средних случайным образом выбирает k точек в качестве центра кластера, вычисляет расстояние между другими точками и центральной точкой, выбирает центр с ближайшим расстоянием и классифицирует его, а также вычисляет новую центральную точку каждого класса после завершения классификации. завершено. Сгруппируйте точки и центральную точку и выберите классификацию с ближайшим расстоянием. Повторяйте этот процесс до тех пор, пока центральная точка больше не изменится.

Идея спектральной кластеризации состоит в том, чтобы рассматривать выборки как вершины, а сходство между выборками — как взвешенные ребра, тем самым превращая проблему кластеризации в задачу сегментации графа: найти метод сегментации графа, чтобы веса ребер, соединяющих разные группы Как можно меньше (что означает, что сходство между группами должно быть как можно меньше), вес ребер внутри группы должен быть как можно выше (что означает, что сходство внутри группы должно быть как можно выше), для достижения цели кластеризации.

3. Идея дистилляции, почему дистилляция?

Перегонка знаний — это перегонка знаний, содержащихся в обученной модели, в другую модель. В частности, дистилляция знаний может передавать знания одной сети в другую сеть, и эти две сети могут быть однородными или разнородными. Подход состоит в том, чтобы сначала обучить сеть учителей, а затем использовать выходные данные сети учителей и истинные метки данных для обучения сети учеников.

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

  • Вывод медленный
  • Высокие требования к ресурсам развёртывания (память, видеопамять и т.д.), у нас жёсткие ограничения по задержке и вычислительным ресурсам при развёртывании.

Поэтому сжатие модели (уменьшение количества параметров модели при сохранении производительности) становится важным вопросом. А «выгонка модели» — это метод сжатия модели.

4. Какие виды дистилляции существуют?Какова студенческая модель в дистилляции?

Возьмем модель Берта в качестве примера:

Logit Distillation

Помимо логит-дистилляции: TinyBert

Дистилляция учебного плана:

Динамический ранний выход: FastBert.

5. Какие оптимизации делает Python в памяти?

Python использует пулы памяти для уменьшения фрагментации памяти и повышения эффективности выполнения. Он в основном завершает сборку мусора за счет подсчета ссылок, решает проблему, вызванную циклической ссылкой на объекты-контейнеры, с помощью пометки и очистки, а также повышает эффективность сборки мусора за счет сбора по поколениям.

6. Как сэкономить память?

  • Вручную перерабатывать ненужные переменные;
  • Преобразование числовых данных в 32-битные или 16-битные (ограничение типа данных)

Пример кода выглядит следующим образом:

def reduce_mem_usage(props):
    # 计算当前内存
    start_mem_usg = props.memory_usage().sum() / 1024 ** 2
    print("Memory usage of the dataframe is :", start_mem_usg, "MB")
    
    # 哪些列包含空值,空值用-999填充。why:因为np.nan当做float处理
    NAlist = []
    for col in props.columns:
        # 这里只过滤了object格式,如果你的代码中还包含其他类型,请一并过滤
        if (props[col].dtypes != object):
            
            print("**************************")
            print("columns: ", col)
            print("dtype before", props[col].dtype)
            
            # 判断是否是int类型
            isInt = False
            mmax = props[col].max()
            mmin = props[col].min()
            
            # Integer does not support NA, therefore Na needs to be filled
            if not np.isfinite(props[col]).all():
                NAlist.append(col)
                props[col].fillna(-999, inplace=True) # 用-999填充
                
            # test if column can be converted to an integer
            asint = props[col].fillna(0).astype(np.int64)
            result = np.fabs(props[col] - asint)
            result = result.sum()
            if result < 0.01: # 绝对误差和小于0.01认为可以转换的,要根据task修改
                isInt = True
            
            # make interger / unsigned Integer datatypes
            if isInt:
                if mmin >= 0: # 最小值大于0,转换成无符号整型
                    if mmax <= 255:
                        props[col] = props[col].astype(np.uint8)
                    elif mmax <= 65535:
                        props[col] = props[col].astype(np.uint16)
                    elif mmax <= 4294967295:
                        props[col] = props[col].astype(np.uint32)
                    else:
                        props[col] = props[col].astype(np.uint64)
                else: # 转换成有符号整型
                    if mmin > np.iinfo(np.int8).min and mmax < np.iinfo(np.int8).max:
                        props[col] = props[col].astype(np.int8)
                    elif mmin > np.iinfo(np.int16).min and mmax < np.iinfo(np.int16).max:
                        props[col] = props[col].astype(np.int16)
                    elif mmin > np.iinfo(np.int32).min and mmax < np.iinfo(np.int32).max:
                        props[col] = props[col].astype(np.int32)
                    elif mmin > np.iinfo(np.int64).min and mmax < np.iinfo(np.int64).max:
                        props[col] = props[col].astype(np.int64)  
            else: # 注意:这里对于float都转换成float16,需要根据你的情况自己更改
                props[col] = props[col].astype(np.float16)
            
            print("dtype after", props[col].dtype)
            print("********************************")
    print("___MEMORY USAGE AFTER COMPLETION:___")
    mem_usg = props.memory_usage().sum() / 1024**2 
    print("Memory usage is: ",mem_usg," MB")
    print("This is ",100*mem_usg/start_mem_usg,"% of the initial size")

7. Как библиотека pandas читает очень большие файлы?

Данные можно читать блоками.

Пример кода выглядит следующим образом:

data_path = r'E:\python\Study\BiGData\demo.csv'
def read_bigfile(path):
    # 分块,每一块是一个chunk,之后将chunk进行拼接
    df = pd.read_csv(path, engine='python', encoding='gbk', iterator=True)  
    loop = True
    chunkSize = 10000
    chunks = []
    while loop:
        try:
            chunk = df.get_chunk(chunkSize)
            chunks.append(chunk)
        except StopIteration:
            loop = False
            print("Iteration is stopped.")
    df = pd.concat(chunks, ignore_index=True)
after_df = read_bigfile(path = data_path)

8. Самая длинная подстрока без повторяющихся символов

Название leetcode-3, сложность: [Средняя]

Метод: двойной указатель + скользящее окно

Определите два указателя start и end, чтобы получить скользящее окно

start изначально равен 0, используйте end для линейного обхода каждого символа и используйте recod для записи последнего нижнего индекса каждой буквы

Возможны два случая: первый — в записи не появился новый символ, что означает отсутствие повторения; другой — в записи появился новый символ char, что указывает на необходимость обновления начала, и максимальное значение между start и record[char]+1 принимается как новое начало.

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

Код:

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        record = {}
        start,res = 0,0
        for end in range(len(s)):
            if s[end] in record:
                start = max(start, record[s[end]] + 1)
            record[s[end]] = end
            res = max(res, end - start + 1)
        return res

Временная сложность: O(n)

Космическая сложность: O(1)

9. Суждениесвязанный списокесть ли кольцо,связанный списоквыход на ринг

Оценка того, имеет ли связанный список цикл, является вопросом leetcode-141

Есть два пути решения проблемы, а именно:

Способ 1: хеш-таблица

Пройдите все узлы, и каждый раз, когда узел будет пройден, определите, был ли этот узел посещен ранее.

Если он был посещен, это означает, что связанный список является циклическим связанным списком, и возвращает True, если нет, узел добавляется в хеш-таблицу, и обход завершен.

код показывает, как показано ниже:

class Solution:
    def hasCycle(self, head: ListNode) -> bool:
        seen = set()
        while head:
            if head in seen:
                return True
            seen.add(head)
            head = head.next
        return False

Временная сложность: O(n)

Космическая сложность: O(n)

Способ 2: быстрые и медленные указатели

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

код показывает, как показано ниже:

class Solution:
    def hasCycle(self, head: ListNode) -> bool:
        fast = slow = head
        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next
            if fast == slow:
                return True
        return False

Временная сложность: O(N)

Космическая сложность: O(1)

связанный списокВход на ринг по вопросам leetcode-142

Идеи решения проблем: используйте быстрые и медленные указатели

Во-первых, нам нужно сделать следующие настройки: пусть связанный список имеет a + b узлов, от головы связанного списка до входа связанного списка (исключая входной узел связанного списка) есть узлы, и в кольце связанного списка имеется b узлов, в то же время установите быстрый указатель на f.шаг, медленный указатель делает s шагов;

Очевидно, поскольку быстрые указатели в два раза медленнее медленных, имеем: f = 2s

Если два указателя встречаются впервые, выполняется условие: f = s + nb (n представляет n колец), то есть быстрый длиннее медленного на длину n колец;

Его можно получить из приведенного выше: когда два указателя встречаются впервые, имеется s = nb, f = 2nb

Проблема, которую нужно решить сейчас, как узнать размер ?

Предположим теперь, что два указателя встречаются впервые:

Для медленного указателя, если медленный указатель идет к входному узлу связанного списка, он делает +nb шагов, а при встрече уже сделал nb шагов, поэтому пусть медленный указатель делает шаг, чтобы перейти к входной узел связанного списка. ;

Для быстрого указателя, если быстрый указатель начинает делать шаг от указателя головы, быстрый указатель также просто переходит к узлу входа связанного списка;

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

код показывает, как показано ниже:

class Solution:
    def detectCycle(self, head: ListNode) -> ListNode:
        fast = slow = head
        while True:
            if not (fast and fast.next):return
            fast = fast.next.next
            slow = slow.next
            if fast == slow:break
        fast = head
        while fast != slow:
            fast = fast.next
            slow = slow.next
        return fast

временная сложностьНА)

космическая сложностьО(1)


В сезон зарядки ИИ откройте сундук с сокровищами и изучите обычный ценовой класс бесплатно!

Также есть 200 бумажных книг и т.д., приходите и присылайте! >>>В сезон зарядки ИИ откройте сундук с сокровищами и изучите полный ценовой класс бесплатно, и 200 бумажных книг будут доставлены бесплатно! -Онлайн июль

Опубликовано только что