AI/機器學習(計算機視覺/NLP)方向面試複習1

HazelXU發表於2024-07-30

1. 判斷滿二叉樹

所有節點的度要麼為0,要麼為2,且所有的葉子節點都在最後一層。

#include <iostream>
using namespace std;
class TreeNode {
public:
	int val;
	TreeNode* left;
	TreeNode* right;
//建立的時候輸入引數x,會把x給val,nullptr給left和right 
	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {};
	TreeNode(int x, TreeNode* l, TreeNode* r) : val(x), left(l), right(r) {};
};
bool isfull(TreeNode* cur) {
	if (cur == nullptr) return true;
	if (cur->left == nullptr && cur->right != nullptr || cur->left != nullptr && cur->right == nullptr) return false;
	if (cur->left != nullptr) {
		isfull(cur->left);
		isfull(cur->right);
	}
	else {
		return true;
	}

}

int main() {
	int x = 1;
	TreeNode* left = new TreeNode(1);
	TreeNode* right = new TreeNode(1);
	TreeNode* root = new TreeNode(1, left, nullptr);
	cout << isfull(root) << endl;

}

重點在於建立一個TreeNode類,並且寫出建構函式,呼叫建構函式建立節點。

2. 給定一個數,求該數的平方根,不用內建函式

二分法求解。遞迴。

float n;
float e = 0.001;
float findsquare(float left, float right) {
	float mid = (left + right) / 2;
	if (mid * mid - n >= 0 && mid * mid - n < e || mid * mid - n <= 0 && mid * mid - n >= -e) {
		return mid;
	}
	else {
		if (mid * mid > n) {
			findsquare(left, mid);
		}
		else {
			findsquare(mid, right);
		}
	}
}
int main() {
	cin >> n;
	cout<< findsquare(0, n)<<endl;

}

3. GAN model 內容

影像生成模型。影像生成模型比較瞭解的兩種是GAN和diffusion。

GAN的基本流程:生成器可以用任何輸出二維圖片的網路,例如DNN或者CNN。

Discriminator一般輸入為圖片,輸出為real或者fake。

每一輪,將reference輸入到discriminator裡判別為real,Generator輸出的輸入到discriminator裡判別為假。

Generator的損失函式和Discriminator的損失函式都是二元交叉熵,也就是評估真實資料的機率,Generator的目標是最大化二元交叉熵,也就是讓假結果都為正,而Discriminator是最小化二元交叉熵,讓假結果都為假。

4. Diffusion model 內容

首先是數學知識:

條件機率公式

基於馬爾科夫假設:當前機率僅與上一刻機率有關,與其他時刻無關。可以把條件機率其他項約掉。

高斯分佈的KL散度公式:

引數重整化:整理出z作為網路輸入,其他兩個作為網路引數,可求梯度的。

多元VAE目標函式,都是根據x推理出z,用z預測x。多元VAE的z有多個。

image

Diffusion Model 主要是兩個過程,先從目標分佈中擴散,得到噪聲分佈,是熵增的過程;

然後是從噪聲分佈中預測出目標分佈。訓練過程就是訓練好這個x,這樣就能在隨機生成(例如高斯分佈 )的噪聲中獲得想要的目標分佈。

擴散過程是p,逆擴散過程是q。漂移量是兩者之間的差。
image

5. 二叉樹的建立,插入和刪除

這裡應該是搜尋二叉樹,左節點小於自己,右節點大於自己。

刪除先不寫了不會

#include<iostream>
using namespace std;

class TreeNode {
public:
	int val;
	TreeNode* left;
	TreeNode* right;
	TreeNode(int x) :val(x), left(nullptr), right(nullptr) {};
	TreeNode(int x, TreeNode* l, TreeNode* r) : val(x), left(l), right(r) {};
};
TreeNode* insert(TreeNode* cur, int x) {
	if (cur == nullptr) {
		return new TreeNode(x);
	}
	if (x < cur->val) {
		cur->left = insert(cur->left, x);
	}
	else if (x > cur->val) {
		cur->right = insert(cur->right, x);
	}
	return cur;

}
//有點複雜,先不寫了
TreeNode* deleteNode(TreeNode* cur, int val) {
	if (cur == nullptr) {
		return cur;
	}

}
int main() {
	int x = 1;
	TreeNode* root = new TreeNode(x);
	insert(root, 2);
}

6. Linux相關命令:

top 檢視程序資訊
df -h 檢視硬碟使用情況
ps aux 檢視所有程序
kill -9 pid 殺死編號為pid的程序
chmod 修改許可權
grep 從檔名中找到包含某個字串的資料
wc -l 統計行數
cut 分割一行內容
echo $PATH | cut -d ':' -f 3,5:輸出PATH用:分割後第3、5列資料
find -name 查詢檔案
vim 瀏覽 
head -3 顯示前三行內容
docker:
docker ps -a 檢視容器
docker attach 恢復容器
docker exec 掛起容器
docker run 跑容器
vim :n 到第n行 dd 刪除當前行 :q!直接退出 :wq儲存退出 gg=G格式化
ssh 登入伺服器 scp -r傳檔案

7. 快速排序

#include <bits/stdc++.h>
using namespace std;
const int N = 100001;
void quicksort(int * arr, int l, int r){
    if(l >= r) return;
    int i = l-1, j = r+1;
    int mid = (l+r) / 2;
    int x = arr[mid];
    while(i<j){
        do i++; while(arr[i] < x) ;
       do j--; while(arr[j] > x) ;
       if(i<j) swap(arr[i],arr[j]);
    }
    quicksort(arr, l,j);
    quicksort(arr, j+1, r);

}
int main(){
    int n;
    cin>>n;
    int arr[N];
    for(int i =0;i<n;i++){
        cin>>arr[i];
    }
    quicksort(arr,0,n-1);
    for(int i =0;i<n;i++){
        cout<<arr[i]<<" ";
    }cout<<endl;
}

總是會忘記的點:先do後while,i和j初始化為l-1和r+1,因為進入dowhile迴圈後會自增or自減。

quicksort(arr, l,j); 這裡不能用i代替j,因為i是一定大於x的,j是小於等於x的。要保證左邊的段是小於等於x,右邊的段是大於等於x。

8. xgboost和deepfm的效能。

(1)xgboost的結構:由多個迴歸決策樹的模型構成。每一步都加入一個新的樹。(前向分佈演算法,用貪心的策略)逐步最佳化基學習器。

最佳化第t棵樹時,前面t-1顆樹的引數是確定的。每輪的目標函式是n個樣本的最小損失+正則項

正則項是前t顆樹的複雜度。它由葉子結點的個數和每個節點值w的平方和決定,正則項是為了防止過擬合的。葉子節點越多,越容易過擬合。節點值大,就會導致這棵樹佔比比較多,也容易過擬合。

在機器學習中,一般透過梯度下降法最佳化引數。但是樹模型是階躍的,不連續的函式求不了梯度。所以xgboost是對每個葉節點求loss。 每個葉結點的loss可以用梯度來算,分別用了一階導數和二階導數也就是Hessian矩陣來找最優的分割點。

(2)xgboost如何用在推薦系統上?

將使用者的上下文資訊作為特徵輸入到xgboost中,預測使用者的點選機率。所以xgboost是做迴歸的,放入到裡面後

因為是迴歸任務,所以每輪迭代是選擇葉節點的分裂點,然後根據分裂點得到一個值,這個值就是點選機率。多個數就是加權求平均。樹的節點個數這些都是超引數。

(3)xgboost如何並行的?

並行時,在最優分裂點時用並行運算加快效率。它對特徵進行分塊,平行計算每個特徵的增益,透過增益找到最佳分割點。再同步結果,選擇最大的特徵進行分割。

xgboost相對於梯度提升樹(GBDT)有啥提升?

引入了二階導數(Hessian),這在最佳化過程中比傳統GBDT(只使用一階導數資訊)更為準確。

(4)Deepfm演算法:

deep factorization machines 因子分解機。它對低階特徵做特徵互動,另外一個DNN神經網路,做高階特徵互動。一般輸出是兩者的加權和。

因子分解機(FM)是什麼?

FM是SVM的擴充,更適合用於處理稀疏特徵。主要考慮到多維特徵之間的交叉關係(就像SVM的核函式,用內積,但是卻是用因子分解引數化的方式,而SVM中用的是稠密引數化的方式,這使得FM相比SVM的引數少了很多,更加容易計算)。其中引數的訓練使用的矩陣分解的方法。

例如對於電影評分中的資料,用onehot向量建模,一個特徵是非常稀疏的,非常長。因子分解機就是一種改進的二階多項式模型,考慮到兩個向量之間的相似性,例如喜歡這個型別電影的對另一個型別電影的喜歡。(推薦系統之FM(因子分解機)模型原理以及程式碼實踐 - 簡書)

本質上是用deepfm給召回階段的候選集合排序。所以做的僅僅只是排序,不是召回。Loss用的是adam。

(5)為什麼在大規模資料集上使用deepfm?

在處理使用者行為資料和隱式反饋資料時,DeepFM透過其深度部分能夠捕捉到複雜的非線性關係,表現較好。在大規模推薦系統中,如廣告推薦、商品推薦等,DeepFM具有優勢。

適合大規模資料和自動特徵學習的場景,尤其在處理高維稀疏特徵時表現出色。但需要大量資料和計算資源才能充分發揮其優勢。

9. 判斷連結串列裡是否有環

可以用雜湊法或者快慢指標法。快慢指標要注意:判斷fast的next。不然會出界,並且初始化兩個指標不能相同,不然當只有一個資料時返回就不對了。

    bool hasCycle(ListNode *head) {
        if (head == nullptr) return false;
        ListNode* slow = head;
        ListNode* fast = head->next;
        while(slow != fast){
            if(fast == nullptr || fast->next == nullptr) return false;
            slow = slow->next;
            fast = fast->next->next;
        }
        return true;
    }

雜湊表法:注意插入是insert

bool hasCycle(ListNode *head) {
        unordered_set<ListNode*> sets;
        ListNode * cur = head;
        while(cur!=nullptr){
            if(sets.count(cur)) return true;
            sets.insert(cur);
            cur = cur->next;
        }
        return false;
    }

10. HDFS相關基礎知識

對hadoop瞭解的不多,主要是使用了一些hadoop的命令進行資料讀取。

HDFS是hadoop distribution file system。HDFS的檔案分佈在伺服器叢集上,提供副本和容錯率保證。

適用於儲存特別大的檔案,採用流式資料進行訪問。但不適合毫秒級別的訪問,是有點延時的。

我是使用了一些命令列的命令,例如:

hadoop fs -copyFromLocal // copy file
hadoop fs mkdir
hadoop fs -ls

相關文章