#include <algorithm>
#include <bitset>
#include <complex>
#include <deque>
#include <exception>
#include <fstream>
#include <functional>
#include <iomanip>
#include <ios>
#include <iosfwd>
#include <iostream>
#include <istream>
#include <iterator>
#include <limits>
#include <list>
#include <locale>
#include <map>
#include <memory>
#include <new>
#include <numeric>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <streambuf>
#include <string>
#include <typeinfo>
#include <utility>
#include <valarray>
#include <vector>
#include <climits>
#include <cstring>
#include <cassert>

#define rep(i, m, n) for(int i=int(m);i<int(n);i++)
#define all(c) begin(c),end(c)

template<typename T1, typename T2>
inline void chmin(T1 &a, T2 b) { if (a > b) a = b; }

template<typename T1, typename T2>
inline void chmax(T1 &a, T2 b) { if (a < b) a = b; }

typedef long long int ll;
using ll = long long int;
using ull = long long unsigned int;
using Int = long long int;
using Double = long double;
using namespace std;
#define INF (1 << 30) - 1
#define INFl (ll)5e15
#define DEBUG 0
#define dump(x)  cerr << #x << " = " << (x) << endl
#define MOD 1000000007


struct BFS01 {
    struct edge {
        ll to, cost;
    };
    typedef pair<ll, ll> P;//firstは最短距離、secondは頂点の番号

    int V;//超点数
    vector<vector<edge> > G;//グラフ,G[i]はiから出る辺の集合,G[i][j]はiから出る辺のj番目の辺
    vector<ll> d; //最短距離

    BFS01(int N) {
        V = N;
        G.resize(N);
        d = vector<ll>(N);
    };

    void addEdge(int from, int to, int cost) {
        edge e;
        e.to = to;
        e.cost = cost;
        G[from].push_back(e);
    }

    void calc(int s) {
//        priority_queue<P,vector<P>,greater<P> > que;
        deque<P> que;
        fill(d.begin(), d.end(), INFl);
        d[s] = 0;
        que.push_back(P(0, s));

        while (!que.empty()) {
            P p = que.front();
            que.pop_front();
            ll v = p.second;
            if (d[v] < p.first) continue;
            for (int i = 0; i < G[v].size(); i++) {
                edge e = G[v][i];
                if (d[e.to] > d[v] + e.cost && !(d[e.to] == INFl && d[v] == INFl)) {
                    d[e.to] = d[v] + e.cost;
                    if (e.cost == 0) {
                        que.push_front(P(d[e.to], e.to));
                    } else {
                        que.push_back(P(d[e.to], e.to));
                    }
                }
            }
        }

    }
};


//edit
const int TOP = 0;
const int FRONT = 1;
const int RIGHT = 2;
const int LEFT = 3;
const int BACK = 4;
const int BOTTOM = 5;
vector<vector<Int>> rot(720, vector<Int>(6));
vector<vector<Int>> dices;

vector<Int> hash_d(Int hash) {
    vector<Int> rest = {1, 2, 3, 4, 5, 6};
    vector<Int> ret;
    Int base = 120;

    for (int i = 0; i < 6; ++i) {
//        ret.push_back(1 + hash / base);
        ret.push_back(rest[hash / base]);
        rest.erase(rest.begin() + hash / base);


        hash %= base;
        if ((5 - i) > 0) {
            base /= 5 - i;
        }
    }

    return ret;
}

Int fact(Int n) {
    if (n > 0) return fact(n - 1) * n;
    return 1;
}

Int d_hash(vector<Int> d) {
    if (d.size() == 1) {
        return 0;
    }
    //今ある数字が何番目に小さいか
    Int cnt = 0;
    Int base = fact(static_cast<Int>(d.size()) - 1);

    for (auto e : d) {
        if (e < d[0]) cnt++;
    }
    Int ret = cnt * base;
    d.erase(d.begin());
    ret += d_hash(d);

    return ret;
//    Int ret = 0;
//    Int base = 1;
//    for (int i = 0; i < 6; ++i) {
//        Int tmp = base * (d[5 - i] - 1);
//        ret += tmp;
//
//        base *= (i + 1);
//    }
//
//    return ret;
}

Int rot_any(Int hash, vector<Int> dir) {
    vector<Int> dice = hash_d(hash);
    vector<Int> val;
    for (auto e : dir) val.push_back(dice[e]);
    rotate(val.begin(), val.begin() + 1, val.end());
    vector<Int> new_dice = dice;

//    for (int i = 0, ii = 0; i < 6; ++i) {
//        if (ii < 4 && i == dir[ii]) {
//            new_dice[i] = val[dir[ii]];
//            ii++;
//        }
//    }

    for (int i = 0; i < 4; ++i) {
        int j = (i + 1) % 4;

        new_dice[dir[i]] = dice[dir[j]];
    }

    return d_hash(new_dice);
}

Int rot_R(Int hash) {
//    vector<Int> dice = hash_d(hash);
    vector<Int> dir = {TOP, LEFT, BOTTOM, RIGHT};
//    vector<Int> val;
//    for (auto e : idx) val.push_back(dice[e]);
//    rotate(val.begin(), val.begin() + 1, val.end());
//    vector<Int> new_dice = dice;
//
//    for (int i = 0, ii = 0; i < 6; ++i) {
//        if (ii < 4 && i == idx[ii]) {
//            new_dice[i] = idx[ii];
//            ii++;
//        }
//    }
//
//    return d_hash(new_dice);

    return rot_any(hash, dir);
}

Int rot_L(Int hash) {
    vector<Int> dir = {TOP, RIGHT, BOTTOM, LEFT};
    return rot_any(hash, dir);
}

Int rot_F(Int hash) {
    vector<Int> dir = {TOP, BACK, BOTTOM, FRONT};
    return rot_any(hash, dir);
}

Int rot_B(Int hash) {
    vector<Int> dir = {TOP, FRONT, BOTTOM, BACK};
    return rot_any(hash, dir);
}

void print_vec(vector<Int> v) {
    for (auto e : v) cout << e << " ";
    cout << endl;
}

class Solve {
public:
    void init() {
        vector<Int> dice = {1, 2, 3, 4, 5, 6};
        do {
            Int hash = d_hash(dice);
            rot[hash][RIGHT] = rot_R(hash);
            rot[hash][LEFT] = rot_L(hash);
            rot[hash][FRONT] = rot_F(hash);
            rot[hash][BACK] = rot_B(hash);
            dices.push_back(dice);
        } while (next_permutation(all(dice)));


    }

    void solve() {
        init();

        Int H, W;
        cin >> H >> W;

        vector<string> S(H);
        for (int i = 0; i < H; ++i) cin >> S[i];

        auto get_cell = [&](Int hash, Int h, Int w) -> Int {
            return w + (W * h) + (W * H * hash);
        };

        auto i_get_cell = [&](Int tapu) {
            Int w = tapu % W;
            Int h = ((tapu - w) / W) % H;
            Int hash = (tapu - w - W * h) / (W * H);
            return make_tuple(hash, h, w);
        };


//        BFS01 neri(W * H * 720);
        queue<Int> que;
        vector<vector<vector<bool>>> tapi(720, vector<vector<bool>>(H, vector<bool>(W, false)));
        tapi[0][0][0] = true;
        que.push(get_cell(0, 0, 0));

        while (!que.empty()) {
            Int val = que.front();
            que.pop();
            Int h, w, hash;
            tie(hash, h, w) = i_get_cell(val);

            vector<Int> dh = {0, 1, 0, -1};
            vector<Int> dw = {1, 0, -1, 0};
            for (int k = 0; k < 4; ++k) {
                Int nh = h + dh[k];
                Int nw = w + dw[k];
                if (!(nh >= 0 && nh < H && nw >= 0 && nw < W)) continue;

                vector<Int> next_dice;
                if (k == 0) {
                    //右へ転がす
//                            next_dice = hash_d(rot_R(hash));
//                            next_dice = hash_d(rot[hash][RIGHT]);
                    next_dice = dices[rot[hash][RIGHT]];
                } else if (k == 1) {
//                            next_dice = hash_d(rot[hash][FRONT]);
                    next_dice = dices[rot[hash][FRONT]];
                } else if (k == 2) {
//                            next_dice = hash_d(rot[hash][LEFT]);
                    next_dice = dices[rot[hash][LEFT]];
                } else {
//                            next_dice = hash_d(rot[hash][BACK]);
                    next_dice = dices[rot[hash][BACK]];
                }

                Int next_hash = d_hash(next_dice);

                //底面が条件に合わなければ飛ばす
                if (next_dice[BOTTOM] + '0' != S[h + dh[k]][w + dw[k]]) {
                    continue;
                }

//                        neri[get_cell(h,w,hash)][]
//                neri.addEdge(get_cell(hash, h, w), get_cell(next_hash, nh, nw), 1);
                if (!tapi[next_hash][nh][nw]) {
                    tapi[next_hash][nh][nw] = true;
                    que.push(get_cell(next_hash, nh, nw));
                }
            }
        }

//        for (int h = 0; h < H; ++h) {
//            for (int w = 0; w < W; ++w) {
//                for (int hash = 0; hash < 720; ++hash) {
//                    //底面がS[h][w]となるものをすべて転がす
////                    if (h == 1 && w == 0 && hash == 489) {
////                        int ei = 13 + 33;
////                    }
//
//                    vector<Int> dice = hash_d(hash);
//
//                    //底面が条件に合わなければ飛ばす
//                    if (dice[BOTTOM] + '0' != S[h][w]) continue;
//
//                    vector<Int> dh = {0, 1, 0, -1};
//                    vector<Int> dw = {1, 0, -1, 0};
//
//                    for (int k = 0; k < 4; ++k) {
//                        Int nh = h + dh[k];
//                        Int nw = w + dw[k];
//                        if (!(nh >= 0 && nh < H && nw >= 0 && nw < W)) continue;
//
//                        vector<Int> next_dice;
//                        if (k == 0) {
//                            //右へ転がす
////                            next_dice = hash_d(rot_R(hash));
////                            next_dice = hash_d(rot[hash][RIGHT]);
//                            next_dice = dices[rot[hash][RIGHT]];
//                        } else if (k == 1) {
////                            next_dice = hash_d(rot[hash][FRONT]);
//                            next_dice = dices[rot[hash][FRONT]];
//                        } else if (k == 2) {
////                            next_dice = hash_d(rot[hash][LEFT]);
//                            next_dice = dices[rot[hash][LEFT]];
//                        } else {
////                            next_dice = hash_d(rot[hash][BACK]);
//                            next_dice = dices[rot[hash][BACK]];
//                        }
//
//                        Int next_hash = d_hash(next_dice);
//
//                        //底面が条件に合わなければ飛ばす
//                        if (next_dice[BOTTOM] + '0' != S[h + dh[k]][w + dw[k]]) {
//                            continue;
//                        }
//
////                        neri[get_cell(h,w,hash)][]
//                        neri.addEdge(get_cell(hash, h, w), get_cell(next_hash, nh, nw), 1);
//                    }
//                }
//            }
//        }

//        neri.calc(get_cell(0, 0, 0));

//        if (!true) {
//            while (true) {
//                Int tmp = 0;
//                cin >> tmp;
//                if (tmp == -1) break;
//
//                for (auto e : neri.G[tmp]) {
//                    Int tapu = e.to;
//                    Int w = tapu % W;
//                    Int h = ((tapu - w) / W) % H;
//                    Int hash = (tapu - w - W * h) / (W * H);
//                    cout << e.to << endl;
//                    cout << hash << " " << w << " " << h << endl;
//                }
//            }
//        }

        for (int i = 0; i < 720; ++i) {
//            if (neri.d[get_cell(i, H - 1, W - 1)] != INFl) {
            if (tapi[i][H - 1][W - 1]) {

                cout << "YES" << endl;
                return;
            }
        }


        cout << "NO" << endl;
    }

};


int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    cout << fixed << setprecision(10);

    Solve().solve();


    return 0;
}



Measured memory_bytes: 8432