#include<iostream>
#include<vector>
#include<algorithm>
#include<map>
#include<set>
#include<string>
#include<cstring>
#include<cstdlib>
#include<cassert>
#include<climits>
 
#define MOD (1000000007)
#define REP(i,s,n) for(int i=s;i<n;i++)
#define rep(i,n) REP(i,0,n)
#define IINF (INT_MAX)
#define MAX 2000
 
using namespace std;
 
typedef long long ull;
typedef pair<int,int> ii;
 
struct Data{
  int  to,cost;
  Data(int to=IINF,int cost=IINF):to(to),cost(cost){}
};
 
// Library - topological sort - begin 
template<typename T>
bool visit(const T& G,int v,vector<int>& order,vector<int>& color)
{
  color[v] = 1;
  for(__typeof((G[v]).begin()) e = G[v].begin();e != G[v].end();e++)
    {
      if(color[e->to] == 2)continue;//このvisit以外のvisitで訪れた
      if(color[e->to] == 1)return false;//このvisitで訪れた
      if(!visit(G,e->to,order,color))return false;
    }
  order.push_back(v);
  color[v] = 2;
  return true;
}
 
template<typename T>
bool topologicalSort(const T& G,vector<int>& order)
{
  int SizeG = G.size();
  vector<int> color(SizeG); 
  for(int u=0;u<SizeG;u++)
    if(!color[u] && !visit(G,u,order,color))
      return false;
  reverse(order.begin(),order.end());
  return true;
}
// Library - topological sort - end
 
int V,E,S,D;
vector<vector<Data> > tmp_G,tmp_rG;
vector<int>  G[MAX];
vector<int> rG[MAX];
vector<int> vs;
bool used[MAX];
int cmp[MAX];
ull dp[MAX];
 
inline void add_edge(int from,int to){
  G[from].push_back(to);
  rG[to].push_back(from);
}
 
void dfs(int v){
  used[v] = true;
  for(int i=0;i<G[v].size();i++)if(!used[G[v][i]])dfs(G[v][i]);
  vs.push_back(v);
}
 
void rdfs(int v,int k){
  used[v] = true;
  cmp[v] = k;
  for(int i=0;i<rG[v].size();i++)if(!used[rG[v][i]])rdfs(rG[v][i],k);
}
 
int scc(){
  memset(used,0,sizeof(used));
  vs.clear();
  for(int v=0;v<V;v++)if(!used[v])dfs(v);
  memset(used,0,sizeof(used));
  int k = 0;
  for(int i = vs.size()-1; i >= 0 ; i-- )if(!used[vs[i]])rdfs(vs[i],k++);
  return k;
}
 
int main(){
 
  cin >> V >> E;
  rep(i,E){
    cin >> S >> D;
    assert(1 <= S && S <= V);
    assert(1 <= D && D <= V);
    add_edge(S-1,D-1);
  }
  int nV = scc();
  rep(i,nV)dp[i] = -1;
 
  set<int> OUT_counter[nV];
  rep(i,V)rep(j,G[i].size()){
    if(cmp[i] == cmp[G[i][j]])continue;
    OUT_counter[cmp[i]].insert(cmp[G[i][j]]);
  }
 
  tmp_G.clear(),tmp_rG.clear();
  tmp_G.resize(nV),tmp_rG.resize(nV);
  rep(i,nV)for(int j : OUT_counter[i]){
    tmp_G[i].push_back(j);
    tmp_rG[j].push_back(i);
  }
 
  vector<int> order;
  topologicalSort(tmp_G,order);
 
  rep(i,nV)if(tmp_rG[order[i]].empty())dp[order[i]] = 2ULL;
 
  ull ans = 1;
  rep(i,nV){
    int cur = order[i];
    ull cost = 1;
    rep(j,tmp_rG[cur].size()) cost = ( cost * dp[tmp_rG[cur][j].to] ) % MOD;
    if(!tmp_rG[cur].empty())  dp[cur] = ( cost + 1ULL ) % MOD;
    if(tmp_G[cur].empty())    ans = ( ans * dp[cur] ) % MOD;
  }
  cout << ans << endl;
  return 0;
}