#include<iostream>
#include<algorithm>
#include<array>
#include<cassert>
#include<vector>

std::vector<std::vector<int>> ad;
std::vector<char> vis;

std::vector<int> deg,par;
void dfs(int x){
	assert(!vis[x]);
	vis[x]=true;
	for(int y:ad[x])if(!vis[y]){
		par[y]=x;
		dfs(y);
	}
}

void dfs2(int x){
	assert(!vis[x]);
	vis[x]=true;
	for(int y:ad[x])if(y!=par[x]&&vis[y]){ // found a cycle (with depth of x smallest possible)
		throw std::pair<int,int>(x,y);
	}
	for(int y:ad[x])if(!vis[y]){
		par[y]=x;
		dfs(y);
	}
}

void solve(){
	int n,m;std::cin>>n>>m;
	if(n==1){
retno:
		std::cout<<"No\n";
		return;
	}
	ad.clear();ad.resize(n); // http://quick-bench.com/gA_4mEfAnrl2lETqG9pkGqad05U
	deg.assign(n,0); // will be ~ 2x faster with -O3
	for(int _=0;_<m;++_){
		int a,b;std::cin>>a>>b;--a;--b;
		ad[a].push_back(b);
		ad[b].push_back(a);
		++deg[a];++deg[b];
	}

	for(int i=0;i<n;++i){
		deg[i]%=3;
		if(deg[i]==0){
			std::cout<<"Yes\n"<<n-1<<'\n';
			for(int j=0;j<n;++j)if(j!=i)
				std::cout<<j+1<<' ';
			std::cout<<'\n';
			return;
		}
	}

	vis.assign(n,false);

	int i=int(std::find(begin(deg),end(deg),1)-begin(deg));
	if(i==n)
		i=0;

	par.assign(n,0);
	par[i]=-1;
	dfs(i);

	if(std::find(begin(vis),end(vis),false)!=end(vis)){
		// multiple connected components. remove the visited component
		std::cout<<"Yes\n"<<std::count(begin(vis),end(vis),true)<<'\n';
		for(int i=0;i<n;++i)
			if(vis[i])
				std::cout<<i+1<<' ';
		std::cout<<'\n';
		return;
	}

	if(std::all_of(begin(ad),end(ad),[](auto const& x){return x.size()<3;}))
		goto retno;

	if(deg[i]==1){
		for(int j=0;j<n;++j)
			if(j!=i&&deg[j]==1){
				assert(vis[j]);

				for(int x=j;x!=i;x=par[x]){
					if(deg[x]==1)
						j=x;
				}
				// now deg[j]==deg[i]==1 and deg of all nodes on path ==2

				vis.assign(n,false);
				int ndelete=n-1;
				vis[i]=true;
				for(int x=j;x!=i;x=par[x]){
					--ndelete;
					vis[x]=true;
				}

				std::cout<<"Yes\n"<<ndelete<<'\n';
				for(int k=0;k<n;++k)
					if(!vis[k]){
						std::cout<<k+1<<' ';
					}
				std::cout<<'\n';
				return;
			}
	}

	// otherwise there's at most one node with degree 1
	for(int j=0;j<n;++j)
		if(j!=i)
			assert(deg[j]==2);
	assert(deg[i]==2 || ad[i].size()>=4);

	// temporarily remove
	if(deg[i]==1)
		for(int j:ad[i])
			ad[j].erase(std::find(begin(ad[j]),end(ad[j]),i));

	vis.assign(n,false);
	std::array<std::pair<int,int>,2> d; int dlen=0; // store 2 paths in the forest

	try{
		decltype(vis) bkp_vis;
		// d: { root, leaf }

		for(int z:ad[i]){ // z: root of current component
			if(!vis[z]){
				par[z]=-1;

				if(dlen<2)bkp_vis=vis;

				dfs2(z);

				if(dlen<2){
					d[dlen].first=z;
					d[dlen].second=-1;
					for(int t:ad[i]) // find a leaf t adjacent to node i
						if(!bkp_vis[t]&&vis[t]&&t!=z){
							d[dlen].second=t;
							break;
						}
					assert(d[dlen].second>=0);
					++dlen;
				}
			}
		}
	}catch(std::pair<int,int> p){ // found a cycle with all vertices deg = 2
		auto [x,y]=p;

		vis.assign(n,false);
		for(int z=x;z!=y;z=par[z])
			vis[z]=true;
		// now all strict descendant of y & ancestor of x are visited

		for(int z:ad[x])if(z!=par[x]&&vis[z]){
			y=z;
			while(vis[z]){
				vis[z]=false;
				z=par[z];
			}
		}
		// now there is no edge x->t | t is a strict descendant of y

		vis[y]=true;

		std::cout<<"Yes\n"<<std::count(begin(vis),end(vis),false)<<'\n';
		for(int j=0;j<n;++j)
			if(!vis[j]){
				std::cout<<j+1<<' ';
			}
		std::cout<<'\n';
		return;
	}

	// the nodes with deg==2 form a forest
	assert(deg[i]==1);
	assert(dlen>=2);

	vis.assign(n,false);
	vis[i]=true;
	for(auto [z,t]:d){
		for(int x=t;;x=par[x]){
			vis[x]=true;
			if(x==z)break;
		}
	}

	int const ndelete=std::count(begin(vis),end(vis),false);
	if(ndelete==0)goto retno;
	std::cout<<"Yes\n"<<ndelete<<'\n';
	for(int j=0;j<n;++j)
		if(!vis[j]){
			std::cout<<j+1<<' ';
		}
	std::cout<<'\n';
}

int main(){
	std::ios::sync_with_stdio(0);std::cin.tie(0);
	int t;std::cin>>t;
	while(t--)
		solve();
}
