#include <bits/stdc++.h>
using namespace std;
template <typename X>
inline X abs(const X& a) {
  return a < 0 ? -a : a;
}
template <typename X>
inline X sqr(const X& a) {
  return a * a;
}
long long combine(long long n, int k) {
  long long ans = 1;
  for (int i = 0; i < k; i++) ans = (ans * (n - i)) / (i + 1);
  return ans;
}
long long pw(long long a, long long p) {
  if (p == 0) return 1;
  if (p == 1) return a;
  long long half = pw(a, p / 2);
  if (p % 2 == 0) return half * half;
  return half * half * a;
}
long long dis(pair<long long, long long> a, pair<long long, long long> b) {
  return (a.first - b.first) * (a.first - b.first) +
         (a.second - b.second) * (a.second - b.second);
}
long long gcd(long long a, long long b) { return b == 0 ? a : gcd(b, a % b); }
long long lcm(long long a, long long b) { return (a * b) / gcd(a, b); }
char cc[100][100];
int mvx[] = {0, 1, -1, 0};
int mvy[] = {1, 0, 0, -1};
int visted[100][100];
bool yep = false;
int n, m;
bool first = true;
void dfs(int i, int j, int ppi, int ppj, int color) {
  for (int k = 0; k < 4 && !yep; k++) {
    int r = i + mvx[k];
    int c = j + mvy[k];
    if (r != ppi && c != ppj && visted[r][c] == 1 && cc[r][c] == color &&
        r >= 0 && c >= 0 && r < n && c < m) {
      yep = true;
      return;
    }
    if (cc[r][c] == color && r >= 0 && c >= 0 && r < n && c < m &&
        visted[r][c] == 0)
      visted[r][c] = 1, dfs(r, c, i, j, color);
  }
}
int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(0);
  cin >> n >> m;
  char h;
  for (int i = 0; i < n; i++)
    for (int j = 0; j < m; j++) {
      cin >> h;
      cc[i][j] = h;
    }
  for (int i = 0; i < n && !yep; i++)
    for (int j = 0; j < m && !yep; j++) {
      memset(visted, 0, sizeof visted);
      visted[i][j] = 1;
      dfs(i, j, i, j, cc[i][j]);
      if (yep) {
        cout << "Yes" << endl;
        return 0;
      }
    }
  cout << "No" << endl;
  return 0;
}
