Counting single degree vertex removal rounds (from a graph)
Naming

Explicit names can go a long way in conveying what a piece of code does. Combine that with unpacking and explicit assignments to name parts of sequences, you can get:

from collections import defaultdict


n, m = map(int, input().split())
edges = [tuple(map(int, input().split())) for _ in range(m)]
adjacents = defaultdict(set)
for node1, node2 in edges:
    adjacent[node1].add(node2)
    adjacent[node2].add(node1)

degrees = defaultdict(set)
for node, neighbours in adjacents.items():
    degrees[len(neighbours].add(node)

if len(degrees[1]) == 0:
    print('0')
else:
    count = 0
    while len(degrees[1]) &gt; 0:
        dec = defaultdict(lambda: [list(), 0])  # Can't figure out a good name for that
        singles = degrees[1]
        while len(singles) &gt; 0:
            single = singles.pop()
            for node in adjacent[single]:
                dec[node][0].append(single)
                dec[node][1] += 1
            del adjacent[single]
        for node, (neighbours, count_neighbours) in dec.items():
            node_degree = len(adjacent[node])
            if node in degrees[node_degree]:
                degrees[node_degree].remove(node)
                degrees[node_degree - count_neighbours].add(node)
                for neighbour in neighbours:
                    adjacent[node].remove(neighbour)
        count += 1
    print(count)


Quick simplifications

We can see from there that some parts are unnecessary complicated: for node in adjacent(single) does not need to be a loop as there must be only one node adjacent to a node with degree 1. You can use unpacking to exctract this value; it will also let you ensure that there was actually only one value there:

while len(singles) &gt; 0:
    single = singles.pop()
    neighbour, = adjacent[single]  # Do not forget the comma here
    del adjacent[single]
    dec[neighbour][0].append(single)
    dec[neighbour][1] += 1


You also have if len(degrees[1]) == 0: ... else: while len(degrees[1]) &gt; 0 which are pretty much the same thing. You can remove the if, if there is no node of degree 1, then the while won't execute and count will still be 0.

Pythonic constructs

Every containers (lists, dicts, strings, sets, …) are considered False in a boolean context if they are empty and True otherwise. Which mean you should write while degrees[1]: or if not degrees[1].

You may also have noticed the use of dict.items() to iterate over both the keys and the values of a dictionnary at the same time. It is more efficient than using the key to retrieve the values latter.

You also don't really need to build a list of edges before building the dictionnary of adjacent nodes:

from collections import defaultdict


_, m = map(int, input().split())

adjacents = defaultdict(set)
for _ in range(m):
    node1, node2 = map(int, input().split())
    adjacent[node1].add(node2)
    adjacent[node2].add(node1)

degrees = defaultdict(set)
for node, neighbours in adjacents.items():
    degrees[len(neighbours].add(node)

count = 0
while degrees[1]:
    dec = defaultdict(lambda: [list(), 0])  # Can't figure out a good name for that
    singles = degrees[1]
    while singles:
        single = singles.pop()
        for node in adjacent[single]:
            dec[node][0].append(single)
            dec[node][1] += 1
        del adjacent[single]
    for node, (neighbours, count_neighbours) in dec.items():
        node_degree = len(adjacent[node])
        if node in degrees[node_degree]:
            degrees[node_degree].remove(node)
            degrees[node_degree - count_neighbours].add(node)
            for neighbour in neighbours:
                adjacent[node].remove(neighbour)
    count += 1

print(count)


Adding and removing nodes

You spend quite a lot of time moving nodes around in various lists and dictionaries. You could simplify the whole thing by using a more straightforward approach:


you only need to keep track of the nodes with degree 1
for each of these nodes:


remove it from its neighbour list of neighbours
if this neighbour now has degree 1, keep track of if in a temporary set

when done, iterate with the new set of nodes with degree 1.




from collections import defaultdict


_, m = map(int, input().split())

adjacents = defaultdict(set)
for _ in range(m):
    node1, node2 = map(int, input().split())
    adjacent[node1].add(node2)
    adjacent[node2].add(node1)

singles = {node for node, neighbours in adjacents.items() if len(neighbours) == 1}
count = 0
while singles:
    new_singles = set()
    for single in singles:
        neighbour, = adjacents[single]
        adjacents[neighbour].remove(single)
        if len(adjacents[neighbour]) == 1:
            new_singles.add(neighbour)
        # del adjacents[single] if you whish but it has no added value here
    singles = new_singles
    count += 1

print(count)


Functions

Using can help make things faster as Python resolves local symbols faster than global ones. But mainly recommended to organise the flow of things better and reuse parts of code.

You should also wrap the top-level code that you don't want to put in a function under an if __name__ == '__main__' clause:

from collections import defaultdict


def remove_singles(adjacents):
    singles = {node for node, neighbours in adjacents.items()
               if len(neighbours) == 1}

    passes = 0
    while singles:
        new_singles = set()
        for single in singles:
            neighbour, = adjacents[single]
            adjacents[neighbour].remove(single)
            if len(adjacents[neighbour]) == 1:
                new_singles.add(neighbour)

        singles = new_singles
        passes += 1

    return passes


if __name__ == '__main__':
    _, m = map(int, input().split())

    graph = defaultdict(set)
    for _ in range(m):
        node1, node2 = map(int, input().split())
        graph[node1].add(node2)
        graph[node2].add(node1)

    print(remove_singles(graph))