#include <bits/stdc++.h>
using namespace std;
using Capacity = int;
struct Edge {
  int src, dst;
  Capacity cap;
  Edge(int s, int d, Capacity c = 0) : src(s), dst(d), cap(c) {}
};
using Edges = vector<Edge>;
using Graph = vector<Edges>;
int N, M;
int a[1000];
int b[1000];
vector<int> tsort(const Graph &g) {
  int n = g.size();
  vector<int> res, vis(n);
  function<bool(int)> dfs = [&](int v) {
    vis[v] = true;
    for (auto &e : g[v])
      if (!vis[e.dst] && !dfs(e.dst)) return false;
    res.push_back(v);
    return true;
  };
  for (int i = 0; i < n; ++i)
    if (!vis[i])
      if (!dfs(i)) return {};
  reverse(res.begin(), res.end());
  return res;
}
pair<vector<int>, Edges> bridge(const Graph &g) {
  const int n = g.size();
  int idx = 0, s = 0, t = 0, k = 0;
  vector<int> ord(n, -1), onS(n), stk(n), roots(n), cmp(n);
  Edges brdg;
  function<void(int, int)> dfs = [&](int v, int u) {
    ord[v] = idx++;
    stk[s++] = v;
    onS[v] = true;
    roots[t++] = v;
    for (auto &e : g[v]) {
      int w = e.dst;
      if (ord[w] == -1)
        dfs(w, v);
      else if (u != w && onS[w])
        while (ord[roots[t - 1]] > ord[w]) --t;
    }
    if (v == roots[t - 1]) {
      brdg.emplace_back(u, v, 0);
      while (1) {
        int w = stk[--s];
        onS[w] = false;
        cmp[w] = k;
        if (v == w) break;
      }
      --t;
      ++k;
    }
  };
  for (int u = 0; u < n; u++) {
    if (ord[u] == -1) {
      dfs(u, n);
      brdg.pop_back();
    }
  }
  return make_pair(cmp, brdg);
}
bool dfs(int now, int start, const Graph &G, vector<bool> &visited) {
  visited[now] = true;
  for (auto nxt : G[now]) {
    if (nxt.dst == start) return false;
    if (!visited[nxt.dst] && !dfs(nxt.dst, start, G, visited)) return false;
  }
  return true;
}
bool isDAG(const Graph &G) {
  int n = G.size();
  for (int i = 0; i < n; i++) {
    vector<bool> visited(n);
    if (!dfs(i, i, G, visited)) return false;
  }
  return true;
}
void dfs2(int v, int pre, const Graph &G, vector<bool> &visited) {
  if (visited[v]) return;
  visited[v] = true;
  for (auto nxt : G[v]) {
    if (v == pre) continue;
    dfs2(nxt.dst, v, G, visited);
  }
}
bool isConnected(const Graph &G) {
  int n = G.size();
  vector<bool> visited(n);
  dfs2(0, -1, G, visited);
  for (int i = 0; i < n; i++) {
    if (!visited[i]) return false;
  }
  return true;
}
int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);
  cin >> N >> M;
  for (int i = 0; i < M; i++) {
    cin >> a[i] >> b[i];
    a[i]--, b[i]--;
  }
  for (int ei = 0; ei < M; ei++) {
    vector<vector<Edge> > G(N), G_dir(N);
    for (int i = 0; i < M; i++) {
      if (i != ei) {
        G[a[i]].push_back(Edge(a[i], b[i]));
        G[b[i]].push_back(Edge(b[i], a[i]));
        G_dir[a[i]].push_back(Edge(a[i], b[i]));
      }
    }
    if (!isConnected(G)) continue;
    auto p = bridge(G_dir);
    if (p.second.size() >= 2 && isDAG(G_dir)) {
      cout << "YES" << endl;
      return 0;
    }
  }
  cout << "NO" << endl;
}
